<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 7.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.ico">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha256-wiz7ZSCn/btzhjKDQBms9Hx4sSeUYsDrTLg7roPstac=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.css" integrity="sha256-6cQIC71/iBIYXFK+0RHAvwmjwWzkWd+r7v/BX3/vZDc=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/themes/green/pace-theme-minimal.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/pace.min.js" integrity="sha256-gqd7YTjg/BtfqWSwsJOvndl0Bxc8gFImLEkXQT8+qj0=" crossorigin="anonymous"></script>

<script class="next-config" data-name="main" type="application/json">{"hostname":"sumumm.github.io","root":"/","images":"/images","scheme":"Gemini","darkmode":false,"version":"8.19.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"fold":{"enable":true,"height":300},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":true,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="本文主要是网络编程——socket编程接口的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:type" content="article">
<meta property="og:title" content="LV06-03-网络编程-02-scoket编程接口">
<meta property="og:url" content="https://sumumm.github.io/post/9661d1ba.html">
<meta property="og:site_name" content="苏木">
<meta property="og:description" content="本文主要是网络编程——socket编程接口的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/LV06-03-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-02-scoket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3/img/image-20220624142104172.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/LV06-03-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-02-scoket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3/img/image-20220625054824336.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/LV06-03-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-02-scoket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3/img/image-20220628162706259.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/LV06-03-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-02-scoket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3/img/image-20220628171626877.png">
<meta property="article:published_time" content="2024-10-27T03:49:36.000Z">
<meta property="article:modified_time" content="2025-06-13T16:25:56.998Z">
<meta property="article:author" content="苏木">
<meta property="article:tag" content="LV06-网络编程">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/LV06-03-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-02-scoket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3/img/image-20220624142104172.png">


<link rel="canonical" href="https://sumumm.github.io/post/9661d1ba.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":"","permalink":"https://sumumm.github.io/post/9661d1ba.html","path":"post/9661d1ba.html","title":"LV06-03-网络编程-02-scoket编程接口"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>LV06-03-网络编程-02-scoket编程接口 | 苏木</title>
  








    <script src="/js/browser_tools_disable.js"></script>

  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
<!-- hexo injector head_end start --><link rel="stylesheet" href="https://unpkg.com/hexo-next-tags-plus@latest/lib/tag_plus.css" media="defer" onload="this.media='all'"><!-- hexo injector head_end end --></head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">苏木</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">我的学习之路</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>苏木的家</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类页<span class="badge">42</span></a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档页<span class="badge">673</span></a></li><li class="menu-item menu-item-flink"><a href="/flink/" rel="section"><i class="fa fa-link fa-fw"></i>友人帐</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于我</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81socket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3"><span class="nav-text">一、socket编程接口</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-socket-%E5%87%BD%E6%95%B0"><span class="nav-text">1. socket()函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">1.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-bind-%E5%87%BD%E6%95%B0"><span class="nav-text">2. bind()函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-sockaddr"><span class="nav-text">2.2 sockaddr</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-sockaddr"><span class="nav-text">2.2.1 sockaddr</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-2-sockaddr-in"><span class="nav-text">2.2.2 sockaddr_in</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-3-sockaddr-in6"><span class="nav-text">2.2.3 sockaddr_in6</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-4-sockaddr-un"><span class="nav-text">2.2.4 sockaddr_un</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-5-%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E7%94%A8sockaddr"><span class="nav-text">2.2.5 为什么不用sockaddr</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-3-INADDR-ANY"><span class="nav-text">2.3 INADDR_ANY</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-4-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.4 使用实例</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-listen-%E5%87%BD%E6%95%B0"><span class="nav-text">3. listen()函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">3.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-%E8%AF%B7%E6%B1%82%E9%98%9F%E5%88%97"><span class="nav-text">3.2 请求队列</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-3-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">3.3 使用实例</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-accept-%E5%87%BD%E6%95%B0"><span class="nav-text">4. accept()函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">4.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-%E5%87%BD%E6%95%B0%E7%90%86%E8%A7%A3"><span class="nav-text">4.2 函数理解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-3-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">4.3 使用实例</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-connect-%E5%87%BD%E6%95%B0"><span class="nav-text">5. connect()函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#5-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">5.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">5.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#6-%E6%96%AD%E5%BC%80%E8%BF%9E%E6%8E%A5%E5%87%BD%E6%95%B0"><span class="nav-text">6. 断开连接函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#6-1-close"><span class="nav-text">6.1 close()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#6-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">6.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#6-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">6.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#6-2-shutdown"><span class="nav-text">6.2 shutdown()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#6-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">6.2.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#6-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">6.2.2 使用实例</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%89%E3%80%81IP%E5%9C%B0%E5%9D%80%E8%BD%AC%E6%8D%A2"><span class="nav-text">三、IP地址转换</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%AD%97%E8%8A%82%E5%BA%8F%E8%BD%AC%E6%8D%A2"><span class="nav-text">1. 字节序转换</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-htonl"><span class="nav-text">1.1 htonl()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">1.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">1.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-htons"><span class="nav-text">1.2 htons()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">1.2.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">1.2.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-ntohl"><span class="nav-text">1.3 ntohl()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-3-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">1.3.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-3-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">1.3.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-ntohs"><span class="nav-text">1.4 ntohs()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-4-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">1.4.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-4-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">1.4.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-IP%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%8D%A2"><span class="nav-text">2.IP字符串转换</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1inet-aton-%E5%87%BD%E6%95%B0"><span class="nav-text">2.1inet_aton()函数</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2inet-addr-%E5%87%BD%E6%95%B0"><span class="nav-text">2.2inet_addr()函数</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.2.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.2.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-3inet-ntoa-%E5%87%BD%E6%95%B0"><span class="nav-text">2.3inet_ntoa()函数</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-3-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.3.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-3-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.3.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-4inet-pton-%E5%87%BD%E6%95%B0"><span class="nav-text">2.4inet_pton()函数</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-4-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.4.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-4-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.4.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-5inet-ntop-%E5%87%BD%E6%95%B0"><span class="nav-text">2.5inet_ntop()函数</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-5-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.5.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-5-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.5.2 使用实例</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%9B%9B%E3%80%81%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93"><span class="nav-text">四、数据传输</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-read-write"><span class="nav-text">1. read()&#x2F;write()</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-read"><span class="nav-text">1.1 read()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-1"><span class="nav-text">1.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B-1"><span class="nav-text">1.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-write"><span class="nav-text">1.2 write()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-1"><span class="nav-text">1.2.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B-1"><span class="nav-text">1.2.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-recv-send"><span class="nav-text">2.recv()&#x2F;send()</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-recv"><span class="nav-text">2.1 recv()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-1"><span class="nav-text">2.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B-1"><span class="nav-text">2.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-send"><span class="nav-text">2.2 send()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-1"><span class="nav-text">2.2.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B-1"><span class="nav-text">2.2.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-recvfrom-sendto"><span class="nav-text">3.recvfrom()&#x2F;sendto()</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-recvfrom"><span class="nav-text">3.1 recvfrom()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">3.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">3.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-sendto"><span class="nav-text">3.2 sendto()</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">3.2.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">3.2.2 使用实例</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%94%E3%80%81socket%E7%BC%93%E5%86%B2%E5%8C%BA%E5%92%8C%E9%98%BB%E5%A1%9E%E6%A8%A1%E5%BC%8F"><span class="nav-text">五、socket缓冲区和阻塞模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-socket%E7%BC%93%E5%86%B2%E5%8C%BA"><span class="nav-text">1. socket缓冲区</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-%E7%BC%93%E5%86%B2%E5%8C%BA%E8%AF%B4%E6%98%8E"><span class="nav-text">1.1 缓冲区说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-TCP%E5%8D%8F%E8%AE%AE%E7%BC%93%E5%86%B2%E5%8C%BA%E5%A4%A7%E5%B0%8F%E8%8E%B7%E5%8F%96"><span class="nav-text">1.2 TCP协议缓冲区大小获取</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-BUFSIZ"><span class="nav-text">1.3 BUFSIZ</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E9%98%BB%E5%A1%9E%E6%A8%A1%E5%BC%8F"><span class="nav-text">2. 阻塞模式</span></a></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="苏木"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">苏木</p>
  <div class="site-description" itemprop="description">莫道桑榆晚，为霞尚满天</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">673</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">42</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
        <span class="site-state-item-count">43</span>
        <span class="site-state-item-name">标签</span>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <a href="https://github.com/sumumm" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;sumumm" rel="noopener me" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
  </div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://sumumm.github.io/post/9661d1ba.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="苏木">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="苏木">
      <meta itemprop="description" content="莫道桑榆晚，为霞尚满天">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="LV06-03-网络编程-02-scoket编程接口 | 苏木">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          LV06-03-网络编程-02-scoket编程接口
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2024-10-27 11:49:36" itemprop="dateCreated datePublished" datetime="2024-10-27T11:49:36+08:00">2024-10-27</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">嵌入式开发</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/" itemprop="url" rel="index"><span itemprop="name">01HQ课程体系</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/" itemprop="url" rel="index"><span itemprop="name">LV06-网络编程</span></a>
        </span>
    </span>

  
    <span class="post-meta-break"></span>
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>17k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>1:03</span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><p>本文主要是网络编程——socket编程接口的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。</p>
<span id="more"></span>

<!-- Photo: https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/LV06-03-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-02-scoket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3/img/ -->

<details class="folding-tag" blue><summary> 点击查看使用工具及版本 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" width=150px>Windows</td>        <td align="left">windows11</td>    </tr>    <tr>        <td align="center">Ubuntu</td>        <td align="left">Ubuntu16.04的64位版本</td>      </tr>    <tr>        <td align="center">VMware® Workstation 16 Pro</td>        <td align="left">16.2.3 build-19376536</td>      </tr>    <tr>        <td align="center">SecureCRT</td>        <td align="left">Version 8.7.2 (x64 build 2214)   -   正式版-2020年5月14日</td>      </tr>    <tr>        <td align="center">开发板</td>        <td align="left">正点原子 i.MX6ULL Linux阿尔法开发板</td>      </tr>    <tr>        <td align="center">uboot</td>        <td align="left">NXP官方提供的uboot，NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)</td>      </tr>    <tr>        <td align="center">linux内核</td>        <td align="left">linux-4.15(NXP官方提供)</td>      </tr>    <tr>        <td align="center">STM32开发板</td>        <td align="left">正点原子战舰V3(STM32F103ZET6)</td>      </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看本文参考资料 </summary>
              <div class='content'>
              <table>    <tr><td align="center">参考方向  </td><td align="center">参考原文</td></tr>    <tr><td align="center">---</td><td align="left"><a href="" target="_blank">--- <i class="fa fa-external-link-alt"></i> </a></td></tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看相关文件下载 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center">---</td>        <td align="left">--- <a href="" target="_blank">  <i class="fa fa-external-link-alt"></i></a></td>      </tr></table>
              </div>
            </details>

<h1 id="一、socket编程接口"><a href="#一、socket编程接口" class="headerlink" title="一、socket编程接口"></a><font size=3>一、<code>socket</code>编程接口</font></h1><p>为了能够正常让客户端能正常连接到服务器，服务器必须遵循以下处理流程：</p>
<p>①、调用 socket()函数打开套接字；</p>
<p>②、调用 bind()函数将套接字与一个端口号以及 IP 地址进行绑定；</p>
<p>③、调用 listen()函数让服务器进程进入监听状态，监听客户端的连接请求；</p>
<p>④、调用 accept()函数处理到来的连接请求。  </p>
<p>接下来就来学习一下这些函数。</p>
<h2 id="1-socket-函数"><a href="#1-socket-函数" class="headerlink" title="1. socket()函数"></a><font size=3>1. <code>socket()</code>函数</font></h2><h3 id="1-1-函数说明"><a href="#1-1-函数说明" class="headerlink" title="1.1 函数说明"></a><font size=3>1.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 2 socket</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">socket</span><span class="params">(<span class="type">int</span> domain, <span class="type">int</span> type, <span class="type">int</span> protocol)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于创建一个网络通信端点（打开一个网络通信），也就是创建一个套接字用于网络通信。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>domain</code>：<code>int</code>类型，用于选择将用于通信的协议族，对于<code>TCP/IP</code>协议来说，通常选择<code>AF_INET</code>就可以了，当然如果我们的<code>IP</code>协议的版本支持<code>IPv6</code>，那么也可以选择<code>AF_INET6</code>。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 domain 常用可取的值及含义 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>domain</td><td align="center">  说明</td><td align="center">帮助页</td></tr>    <tr><td align="left" width=150px>AF_UNIX</td><td align="left" rowspan="2">Local communication</td><td align="left" rowspan="2"> unix(7)</td></tr>    <tr><td align="left" width=150px>AF_LOCAL</td></tr>    <tr><td align="left" width=150px>AF_INET</td><td align="left">IPv4 Internet protocols</td><td align="left"> ip(7)</td></tr>    <tr><td align="left" width=150px>AF_INET6</td><td align="left">IPv6 Internet protocols</td><td align="left"> ipv6(7)</td></tr>    <tr><td align="left" width=150px>AF_IPX</td><td align="left">IPX - Novell protocols</td><td align="left"> </td></tr>    <tr><td align="left" width=150px>AF_NETLINK</td><td align="left">Kernel user interface device</td><td align="left"> netlink(7)</td></tr>    <tr><td align="left" width=150px>AF_X25</td><td align="left">ITU-T X.25 / ISO-8208 protocol</td><td align="left"> x25(7)</td></tr>    <tr><td align="left" width=150px>AF_AX25</td><td align="left">Amateur radio AX.25 protocol</td><td align="left"> ax25(4)</td></tr>    <tr><td align="left" width=150px>AF_PACKET</td><td align="left">Low-level packet interface</td><td align="left"> packet(7)</td></tr>    <tr><td align="left" width=150px>AF_ALG</td><td align="left">Interface to kernel crypto API</td><td align="left"> </td></tr>    <tr><td align="left" width=150px>AF_APPLETALK</td><td align="left">AppleTalk</td><td align="left"> ddp(7)</td></tr></table>
              </div>
            </details>

<ul>
<li><code>type</code>：<code>int</code>类型，用于指定套接字的类型。常用的有 <code>SOCK_STREAM</code>（流格式套接字&#x2F;面向连接的套接字） 和 <code>SOCK_DGRAM</code>（数据报套接字&#x2F;无连接的套接字）。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 type 常见取值及含义 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>type</td><td align="center">说明</td></tr>    <tr><td align="left" width=150px>SOCK_STREAM</td><td align="left">流式套接字，提供有序的、可靠的、双向的、基于连接的字节流，能保证数据正确传送到对方，用于TCP协议；可以支持带外数据传输机制。</td></tr>    <tr><td align="left" width=150px>SOCK_DGRAM</td><td align="left">数据报套接字固定长度的、无连接的、不可靠的报文传递，用于UDP协议。</td></tr>    <tr><td align="left" width=150px>SOCK_SEQPACKET</td><td align="left">固定长度的、有序的、可靠的、面向连接的报文传递。</td></tr>    <tr><td align="left" width=150px>SOCK_RAW</td><td align="left">原始套接字，它允许应用程序访问网络层的原始数据包，这个套接字用得比较少。</td></tr>    <tr><td align="left" width=150px>SOCK_RDM</td><td align="left">提供不保证排序的可靠数据报层。</td></tr>    <tr><td align="left" width=150px>SOCK_PACKET</td><td align="left">已过时，不应在应用程序中使用。</td></tr></table>
              </div>
            </details>

<ul>
<li><code>protocol</code>：<code>int</code>类型，表示传输协议，该参数通常设置为<code>0</code>，表示为给定的通信域和套接字类型选择默认协议。当对同一域和套接字类型支持多个协议时，可以使用<code>protocol</code>参数选择一个特定协议。在<code>AF_INET</code>通信域中，套接字类型为<code>SOCK_STREAM</code>的默认协议是传输控制协议（<code>Transmission Control Protocol</code>，<code>TCP</code>协议），套接字类型为<code>SOCK_DGRAM</code>的默认协议是<code>UDP</code>。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回一个文件描述符，该描述符一般被称为称为<code>socket</code>描述符，该文件描述符将会用于网络通信；失败返回<code>-1</code>，并设置<code>errno</code>表示错误类型。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> socket_fd = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>); <span class="comment">/* 创建套接字 */</span></span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h3 id="1-2-使用实例"><a href="#1-2-使用实例" class="headerlink" title="1.2 使用实例"></a><font size=3>1.2 使用实例</font></h3><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> arc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> socket_fd = <span class="number">-1</span>; <span class="comment">/* 定义一个socket文件描述符 */</span></span><br><span class="line">	socket_fd = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>); <span class="comment">/* 创建套接字 */</span></span><br><span class="line">	<span class="keyword">if</span> (socket_fd &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;socket error&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;socket_fd = %d\n&quot;</span>, socket_fd);</span><br><span class="line">	close(socket_fd);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">socket_fd = 3</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h2 id="2-bind-函数"><a href="#2-bind-函数" class="headerlink" title="2. bind()函数"></a><font size=3>2. <code>bind()</code>函数</font></h2><h3 id="2-1-函数说明"><a href="#2-1-函数说明" class="headerlink" title="2.1 函数说明"></a><font size=3>2.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 2 bind</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">bind</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">const</span> <span class="keyword">struct</span> sockaddr *addr, <span class="type">socklen_t</span> addrlen)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于将一个<code>IP</code>地址和端口号与一个套接字进行绑定（将套接字与地址进行关联）。一般来讲，会将一个服务器的套接字绑定到一个众所周知的地址——即一个固定的与服务器进行通信的客户端应用程序提前就知道的地址（注意这里说的地址包括<code>IP</code>地址和端口号）。因为对于客户端来说，它与服务器进行通信，首先需要知道服务器的<code>IP</code>地址以及对应的端口号，所以通常服务器的<code>IP</code>地址以及端口号都应该是众所周知的。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><p><code>sockfd</code>：<code>int</code>类型，表示要进行绑定的<code>socket</code>描述符。</p>
</li>
<li><p><code>addr</code>：<code>struct sockaddr</code>类型的结构体指针变量，指向一个<code>struct sockaddr</code>类型变量，该结构体中含有要绑定的<code>IP</code>地址及端口号。但是呢，我们一般不使用这个类型，一般会使用<code>struct sockaddr_in</code>类型，具体原因后边的<code>2.2</code>节会详细说明。</p>
</li>
<li><p><code>addrlen</code>：<code>socklen_t</code>类型，用于指定<code>addr</code>所指向的结构体对应的字节长度。</p>
</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>；失败返回<code>-1</code>，并设置<code>errno</code>表示错误类型。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>              <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* bind */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span>         <span class="comment">/* bind */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;strings.h&gt;</span>            <span class="comment">/* bzero exit */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span>          <span class="comment">/* htons htonl */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">sin</span>;</span></span><br><span class="line">bzero (&amp;<span class="built_in">sin</span>, <span class="keyword">sizeof</span> (<span class="built_in">sin</span>));</span><br><span class="line"><span class="built_in">sin</span>.sin_family = AF_INET;           <span class="comment">/* 设置协议族 */</span></span><br><span class="line"><span class="built_in">sin</span>.sin_port = htons (SERV_PORT);	<span class="comment">/* 网络字节序的端口号, 一个自定义宏 */</span></span><br><span class="line"><span class="built_in">sin</span>.sin_addr.s_addr = htonl (INADDR_ANY);<span class="comment">/* 可以绑定任意IP，后边说明 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (bind (fd, (<span class="keyword">struct</span> sockaddr *) &amp;<span class="built_in">sin</span>, <span class="keyword">sizeof</span> (<span class="built_in">sin</span>)) &lt; <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line">	perror(<span class="string">&quot;bind&quot;</span>);</span><br><span class="line">	<span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>socket()</code> 函数用来创建套接字，确定套接字的各种属性，然后服务器端要用 <code>bind()</code> 函数将套接字与特定的 <code>IP</code> 地址和端口绑定起来，只有这样，流经该 <code>IP</code> 地址和端口的数据才能交给套接字处理。所以一般来讲，我们在运行服务器端时，若是绑定固定的<code>IP</code>的话，这个<code>IP</code>需要是<strong>本地所具有</strong>的的<code>IP</code>，否则可能会报以下错误：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Cannot assign requested address</span><br></pre></td></tr></table></figure>

<h3 id="2-2-sockaddr"><a href="#2-2-sockaddr" class="headerlink" title="2.2 sockaddr"></a><font size=3>2.2 <code>sockaddr</code></font></h3><p>这一节就来了解一下这俩结构体之间的关系，以及为什么要使用<code>sockaddr_in</code>，其实还有一个<code>sockaddr_in6</code>，这里就一起说明了。</p>
<h4 id="2-2-1-sockaddr"><a href="#2-2-1-sockaddr" class="headerlink" title="2.2.1 sockaddr"></a><font size=3>2.2.1 <code>sockaddr</code></font></h4><p>在使用<code>man</code>查看<code>bind</code>函数的帮助手册的时候，会有这个结构体的说明：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">sa_family_t</span> sa_family;</span><br><span class="line">	<span class="type">char</span>        sa_data[<span class="number">14</span>];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>【结构体成员说明】</strong></p>
<ul>
<li><code>sa_family</code>表示协议族，它占用<code>2</code>个字节；</li>
<li><code>sa_data</code>是一个<code>char</code>类型的数组，它一共有<code>14</code>个字节，这<code>14</code>个字节中就包括了<code>IP</code>地址、端口号等信息。</li>
</ul>
<p>【注意事项】这个结构对用户并不友好，它把这些信息都封装在了<code>sa_data</code>数组中，这样使得我们是无法对<code>sa_data</code>数组进行赋值。事实上，这是一个<strong>通用</strong>的<code>socket</code>地址结构体，一般来讲我们并不会直接使用，而是会选择另一种结构体，然后进行强制类型转换。</p>
<h4 id="2-2-2-sockaddr-in"><a href="#2-2-2-sockaddr-in" class="headerlink" title="2.2.2 sockaddr_in"></a><font size=3>2.2.2 <code>sockaddr_in</code></font></h4><p>这个结构体比较奇怪，我看到了三种定义的形式，但是呢，其实他们都是一样的，我们在使用的过程中，正常我们都会看到前两种的定义：</p>
<div class="tabs" id="tabname1"><ul class="nav-tabs"><li class="tab active"><a href="#tabname1-1">形式一</a></li><li class="tab"><a href="#tabname1-2">形式二</a></li><li class="tab"><a href="#tabname1-3">形式三</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname1-1"><p>这种定义形式是在网上见的最多的，我上培训班的课程时，老师也是这样来讲的：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">sa_family_t</span> sin_family;  <span class="comment">/* 协议族 2个字节*/</span></span><br><span class="line">	<span class="type">in_port_t</span> sin_port;      <span class="comment">/* 端口号 2个字节共8位*/</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">sin_addr</span>;</span> <span class="comment">/* IP 地址 4个字节共32位*/</span></span><br><span class="line">	<span class="type">unsigned</span> <span class="type">char</span> sin_zero[<span class="number">8</span>]; <span class="comment">/* 填充补位用的，大小为16-2-2-4=8个字节 */</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Internet address. */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">uint32_t</span>       s_addr;     <span class="comment">/* address in network byte order 注意：符合网络字节序 */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="tabname1-2"><p>经过资料查阅，发现使用<code>man 7 ip</code>命令查看帮助手册，也会发现该结构体的定义，定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">sa_family_t</span>    sin_family; <span class="comment">/* address family: AF_INET 2字节 */</span></span><br><span class="line">	<span class="type">in_port_t</span>      sin_port;   <span class="comment">/* port in network byte order 2字节 */</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">sin_addr</span>;</span>   <span class="comment">/* internet address 4字节 */</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Internet address. */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">uint32_t</span>       s_addr;     <span class="comment">/* address in network byte order 注意：符合网络字节序 */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="tabname1-3"><p>我从网上搜了一下，这个结构体在<code>netinet/in.h</code>文件中有定义，结构体成员如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Structure describing an Internet socket address.  */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	__SOCKADDR_COMMON (sin_);</span><br><span class="line">	<span class="type">in_port_t</span> sin_port;                 <span class="comment">/* Port number.  */</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">sin_addr</span>;</span>            <span class="comment">/* Internet address.  */</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">/* Pad to size of `struct sockaddr&#x27;.  */</span></span><br><span class="line">	<span class="type">unsigned</span> <span class="type">char</span> sin_zero[<span class="keyword">sizeof</span> (<span class="keyword">struct</span> sockaddr) -</span><br><span class="line">	                              __SOCKADDR_COMMON_SIZE -</span><br><span class="line">	                              <span class="keyword">sizeof</span> (<span class="type">in_port_t</span>) -</span><br><span class="line">	                              <span class="keyword">sizeof</span> (<span class="keyword">struct</span> in_addr)];</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>但是好像跟我们平时用的不太一样，这个<code>__SOCKADDR_COMMON</code>是什么？它其实是一个宏，它定义在<code>sockaddr.h</code>文件中，我们在终端使用以下命令即可查找该文件所在：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">locate sockaddr.h</span><br></pre></td></tr></table></figure>

<p>当我们打开这个文件，找到<code>__SOCKADDR_COMMON</code>的定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> __SOCKADDR_COMMON(sa_prefix) \</span></span><br><span class="line"><span class="meta">  sa_family_t sa_prefix##family</span></span><br></pre></td></tr></table></figure>

<p>它与 <code>##</code> 连接，表示一个预处理器操作，像上边结构体中成员为：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__SOCKADDR_COMMON (sin_);</span><br></pre></td></tr></table></figure>

<p>它在预处理完成后将会变成下边的形式：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">sa_family_t</span> sin_family</span><br></pre></td></tr></table></figure>

<p>这样一来，这种形式的结构体定义就与形式一保持一致了，甚至还要比形式一更加的严谨。</p></div></div></div>

<p>上边的三种形式，其实我们按照形式一来理解是比较容易理解的，形式一的结构体中：</p>
<ul>
<li><p>第一个成员是<code>sin_family</code>，占<code>2</code>个字节共<code>8</code>位，这与<code>sockaddr</code>结构体是一致的；</p>
</li>
<li><p>第二个成员是<code>sin_port</code>，占<code>2</code>个字节共<code>8</code>位，表示端口号；</p>
</li>
<li><p>第三个成员是<code>sin_addr</code>，这是一个结构体，<code>struct in_addr</code>类型的结构体成员变量，该结构体内部只有一个成员，就是<code>s_addr</code>，占<code>4</code>个字节共<code>32</code>位，表示<code>IP</code>地址，这里需要注意的是，给该成员赋值的时候，一定要先将<code>IP</code>地址通过函数转换为网络字节序。</p>
</li>
<li><p>第四个成员是<code>sin_zero</code>，这是一个<code>unsigned char</code>类型的数组，这个用于占位的，没有什么实际含义，一般使用 <code>memset() </code>函数填充为 <code>0</code>。</p>
</li>
</ul>
<p>所以，<code>sockaddr_in</code>结构体实际上是下图这个样子，它是一个保存<code>IPv4</code>地址的结构体。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/LV06-03-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-02-scoket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3/img/image-20220624142104172.png" alt="image-20220624142104172" style="zoom: 33%;" />

<h4 id="2-2-3-sockaddr-in6"><a href="#2-2-3-sockaddr-in6" class="headerlink" title="2.2.3 sockaddr_in6"></a><font size=3>2.2.3 <code>sockaddr_in6</code></font></h4><p>这个结构体在<code>netinet/in.h</code>文件中有定义：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in6</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="comment">/* sa_family_t sin6_family */</span></span><br><span class="line">	__SOCKADDR_COMMON (sin6_);  <span class="comment">/* 将会被替换成 sa_family_t sin6_family */</span></span><br><span class="line">	<span class="type">in_port_t</span> sin6_port;        <span class="comment">/* Transport layer port # */</span></span><br><span class="line">	<span class="type">uint32_t</span> sin6_flowinfo;     <span class="comment">/* IPv6 flow information */</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">in6_addr</span> <span class="title">sin6_addr</span>;</span>  <span class="comment">/* IPv6 address */</span></span><br><span class="line">	<span class="type">uint32_t</span> sin6_scope_id;     <span class="comment">/* IPv6 scope-id */</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* IPv6 address */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in6_addr</span></span></span><br><span class="line"><span class="class">  &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">union</span></span></span><br><span class="line"><span class="class">      &#123;</span></span><br><span class="line">        <span class="type">uint8_t</span> __u6_addr8[<span class="number">16</span>];  <span class="comment">/* uint8_t: unsigned char */</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined __USE_MISC || defined __USE_GNU</span></span><br><span class="line">        <span class="type">uint16_t</span> __u6_addr16[<span class="number">8</span>];<span class="comment">/* uint16_t: unsigned short int */</span></span><br><span class="line">        <span class="type">uint32_t</span> __u6_addr32[<span class="number">4</span>];<span class="comment">/* uint16_t: unsigned int */</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">      &#125; __in6_u;</span><br></pre></td></tr></table></figure>

<p>这个结构体，与上边的就很类似了，它是一个保存<code>IPv6</code>地址的结构体，成员介绍如下：</p>
<ul>
<li><code>sin6_family</code>：<code>sa_family_t</code>类型，协议族，取值为<code>AF_INET6</code>，占<code>2</code>个字节。</li>
<li><code>sin6_port</code>：<code>in_port_t</code>类型，端口号，占<code>2</code>个字节。</li>
<li><code>sin6_flowinfo</code>：<code>uint32_t</code>类型，<code>IPv6</code>流信息，占<code>4</code>个字节。</li>
<li><code>sin6_addr</code>：<code>struct in6_addr</code>类型结构体变量，具体的<code>IPv6</code>地址，占<code>4</code>个字节。</li>
<li><code>sin6_scope_id</code>：<code>uint32_t</code>类型，接口范围<code>ID</code>，占<code>4</code>个字节。</li>
</ul>
<p>后来发现，该结构体的定义信息我们可以使用<code>man 7 ipv6</code>来打开帮助手册，里边就有这个结构体的详细定义及说明。</p>
<h4 id="2-2-4-sockaddr-un"><a href="#2-2-4-sockaddr-un" class="headerlink" title="2.2.4 sockaddr_un"></a><font size=3>2.2.4 <code>sockaddr_un</code></font></h4><p>接下来介绍另一个结构体，在后边是用于<code>UNIX</code>域套接字的绑定信息，在这里也提一下把，在后边学习<code>UNIX</code>域套接字的时候会深入学习，这个结构体的成员为：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_un</span> </span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">sa_family_t</span> sun_family;               <span class="comment">/* AF_UNIX */</span></span><br><span class="line">	<span class="type">char</span>        sun_path[<span class="number">108</span>];            <span class="comment">/* Pathname */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>这个结构体定义在哪里呢？我们可以通过以下命令查看：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">man 7 unix</span><br></pre></td></tr></table></figure>

<p>这样我们便会打开关于<code>unix</code>的帮助手册，里边就有该结构体的说明。</p>
<p><strong>【成员说明】</strong></p>
<ul>
<li><code>sun_family</code>：<code>sa_family_t</code>类型，协议族，该字段总是包含<code>AF_UNIX</code>。</li>
<li><code>sun_path</code>：<code>char</code>类型，一个系统文件的绝对路径。</li>
</ul>
<h4 id="2-2-5-为什么不用sockaddr"><a href="#2-2-5-为什么不用sockaddr" class="headerlink" title="2.2.5 为什么不用sockaddr"></a><font size=3>2.2.5 为什么不用<code>sockaddr</code></font></h4><p>经过上边的介绍，我们已经了解了这三个结构体，现在来说一说为什么不用<code>sockaddr</code>结构体。</p>
<p><code>sockaddr</code> 和 <code>sockaddr_in</code> 的长度相同，都是<code>16</code>字节，只是将<code>IP</code>地址和端口号合并到一起，用一个成员 <code>sa_data</code> 表示。要想给 <code>sa_data</code> 赋值，必须同时指明<code>IP</code>地址和端口号，例如<code>127.0.0.1:80</code>，可是呢，没有相关函数将这个字符串转换成需要的形式，也就很难给 <code>sockaddr</code> 类型的变量赋值，所以使用 <code>sockaddr_in</code> 和<code>sockaddr_in6</code>来代替。这两个结构体的长度相同，强制转换类型时不会丢失字节，也没有多余的字节。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/LV06-03-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-02-scoket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3/img/image-20220625054824336.png" alt="image-20220625054824336" style="zoom: 43%;" />





<h3 id="2-3-INADDR-ANY"><a href="#2-3-INADDR-ANY" class="headerlink" title="2.3 INADDR_ANY"></a><font size=3>2.3 <code>INADDR_ANY</code></font></h3><p>会发现前边的使用了这东西，那这个到底是啥呢？</p>
<p><code>INADDR_ANY</code>转换过来就是<code>0.0.0.0</code>，泛指本机的意思，也就是表示本机的所有<code>IP</code>，因为有些服务器可能不止一块网卡，多网卡的情况下，这个就表示所有网卡<code>IP</code>地址的意思。</p>
<p>比如如果我们的电脑有<code>3</code>块网卡，分别连接三个网络，那么这台电脑就有<code>3</code>个<code>IP</code>地址了，如果某个应用程序需要监听某个端口，那需要监听哪个网卡地址的端口呢？</p>
<p>如果绑定某个具体的<code>IP</code>地址，那我们只能监听我们所设置的<code>IP</code>地址所在的网卡的端口，我们是无法监听其它两块网卡端口的，如果我们需要三个网卡都监听，那就需要绑定<code>3</code>个<code>IP</code>，也就等于需要管理<code>3</code>个套接字进行数据交换，这样的话就会很麻烦。</p>
<p>为了解决这个问题，于是出现了<code>INADDR_ANY</code>，我们使用<code>bind()</code>只需绑定<code>INADDR_ANY</code>，这样我们就只需要管理一个套接字了，不管数据是从哪个网卡过来的，只要是绑定的端口号过来的数据，都可以接收到。这个宏在<code>Linux</code>中的<code>netinet/in.h</code>文件中进行了定义：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Address to accept any incoming messages.  */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> INADDR_ANY              ((in_addr_t) 0x00000000)</span></span><br></pre></td></tr></table></figure>

<p>这个地址看起来还是比较容易转换的，就是<code>0.0.0.0</code>。在使用的时候<strong>最好是进行一下网络字节序的转换</strong>。</p>
<p>【注意事项】使用该宏与直接使用<code>&quot;0.0.0.0&quot;</code>作为<code>IP</code>绑定的效果是一样的，只是使用字符串<code>&quot;0.0.0.0&quot;</code>的话需要先转换为二进制，还需要注意网络字节序。</p>
<h3 id="2-4-使用实例"><a href="#2-4-使用实例" class="headerlink" title="2.4 使用实例"></a><font size=3>2.4 使用实例</font></h3><p>暂无。</p>
<h2 id="3-listen-函数"><a href="#3-listen-函数" class="headerlink" title="3. listen()函数"></a><font size=3>3. <code>listen()</code>函数</font></h2><h3 id="3-1-函数说明"><a href="#3-1-函数说明" class="headerlink" title="3.1 函数说明"></a><font size=3>3.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 2 listen</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>              <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">listen</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">int</span> backlog)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数<strong>只能在服务器进程中使用</strong>，让服务器进程被动进入监听状态，等待客户端的连接请求。它一般在<code>bind()</code>函数之后调用，在<code>accept()</code>函数之前调用。被动监听就是，当没有客户端请求时，套接字处于睡眠状态，只有当接收到客户端请求时，套接字才会被唤醒来响应请求。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sockfd</code>：<code>int</code>类型，表示已经创建的<code>socket</code>描述符，就是需要进入监听状态的套接字。</li>
<li><code>backlog</code>：<code>int</code>类型，表示用来描述<code>sockfd</code>的等待连接队列能够达到的最大值，一般填<code>5</code>， 测试得知，<code>ARM</code>最大为<code>8</code>。如果将 <code>backlog</code> 的值设置为 <code>SOMAXCONN</code>，就由系统来决定请求队列长度，这个值一般比较大，可能是几百，或者更多。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>；失败返回<code>-1</code>，并设置<code>errno</code>表示错误类型。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="keyword">if</span> (listen (fd, BACKLOG) &lt; <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line">	perror (<span class="string">&quot;listen&quot;</span>);</span><br><span class="line">	<span class="built_in">exit</span> (<span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>（1）无法在一个已经连接的套接字（即已经成功执行 connect()的套接字或由 accept()调用返回的套接字）上<br>执行 listen()。  </p>
<h3 id="3-2-请求队列"><a href="#3-2-请求队列" class="headerlink" title="3.2 请求队列"></a><font size=3>3.2 请求队列</font></h3><p>在服务器进程正处理客户端连接请求的时候，可能还存在其它的客户端请求建立连接，因为<code>TCP</code>连接是一个过程，需要经过三次握手，当同时尝试连接的用户过多时，就会使得服务器进程无法快速地完成所有的连接请求。</p>
<p>那这个时候怎么处理上边的问题呢？直接丢掉其他客户端的连接肯定不是一个很好的解决方法。内核会在自己的进程空间里维护一个队列，这个队列就叫<strong>请求队列</strong>（<code>Request Queue</code>）。这些连接请求就会被放入请求队列中，服务器进程会按照先来后到的顺序去处理这些连接请求，而这样的一个队列必须有一个大小的上限，这个<code>backlog</code>参数告诉内核使用这个数值作为请求队列的上限。而当一个客户端的连接请求到达并且该队列为满时，客户端可能会收到一个表示连接失败的错误，本次请求会被丢弃不作处理。</p>
<p>当请求队列满时，就不再接收新的请求，对于 <code>Linux</code>，客户端会收到 <code>ECONNREFUSED</code> 错误，对于 <code>Windows</code>，客户端会收到 <code>WSAECONNREFUSED</code> 错误。</p>
<h3 id="3-3-使用实例"><a href="#3-3-使用实例" class="headerlink" title="3.3 使用实例"></a><font size=3>3.3 使用实例</font></h3><p>暂无。</p>
<h2 id="4-accept-函数"><a href="#4-accept-函数" class="headerlink" title="4. accept()函数"></a><font size=3>4. <code>accept()</code>函数</font></h2><h3 id="4-1-函数说明"><a href="#4-1-函数说明" class="headerlink" title="4.1 函数说明"></a><font size=3>4.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 2 accept</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">accept</span><span class="params">(<span class="type">int</span> sockfd, <span class="keyword">struct</span> sockaddr *addr, <span class="type">socklen_t</span> *addrlen)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数通常只在服务器端进程中使用，已经进入监听状态的服务器会等待客户端的连接请求，该函数就是用于获取客户端的连接请求并建立连接。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sockfd</code>：<code>int</code>类型，表示已经创建的<code>socket</code>描述符，就是已经进入监听状态的套接字。</li>
<li><code>addr</code>：<code>struct sockaddr</code>类型的结构体指针变量，这是一个<strong>传出参数</strong>。指向一个<code>struct sockaddr</code>类型变量，该结构体中会保存成功连接到服务器端的客户端的<code>IP</code>地址及端口号。但是呢，和上边一样，我们一般不使用这个类型，一般会使用<code>struct sockaddr_in</code>类型。但是如果我们对客户端的<code>IP</code>地址与端口号这些信息不感兴趣，可以把<code>addr</code>置为空指针<code>NULL</code>。</li>
<li><code>addrlen</code>：<code>socklen_t</code>类型指针变量，注意与<code>bind()</code>函数的不同，<code>bind()</code>得这个参数传入的是一个值，而这个函数传入的是一个地址，这个参数用于指定<code>addr</code>所指向的结构体对应的字节长度，一般由<code>sizeof</code>求得。如果<code>addr</code>置为空指针<code>NULL</code>，这个参数其实就没有什么太大意义了，就可以也置<code>NULL</code>。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回一个新的<code>socket</code>描述符，这样我们就会拥有两个<code>socket</code>描述符，一个是原来的，可以继续用于监听，新的文件描述符可以用于发送和接收数据，失败返回<code>-1</code>，并设置<code>errno</code>表示错误类型。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>              <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> newfd = <span class="number">-1</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">cin</span>;</span></span><br><span class="line"><span class="type">socklen_t</span> addrlen = <span class="keyword">sizeof</span> (<span class="built_in">cin</span>);</span><br><span class="line"><span class="keyword">if</span> ((newfd = accept (fd, (<span class="keyword">struct</span> sockaddr *) &amp;<span class="built_in">cin</span>, &amp;addrlen)) &lt; <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line">	perror (<span class="string">&quot;accept&quot;</span>);</span><br><span class="line">	<span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h3 id="4-2-函数理解"><a href="#4-2-函数理解" class="headerlink" title="4.2 函数理解"></a><font size=3>4.2 函数理解</font></h3><p>为了能够正常让客户端能正常连接到服务器，服务器必须遵循以下处理流程：</p>
<ul>
<li>调用<code>socket()</code>函数打开套接字；</li>
<li>调用<code>bind()</code>函数将套接字与一个端口号以及<code>IP</code>地址进行绑定；</li>
<li>调用<code>listen()</code>函数让服务器进程进入监听状态，监听客户端的连接请求；</li>
<li>调用<code>accept()</code>函数处理到来的连接请求。</li>
</ul>
<p><code>accept()</code>函数通常只用于服务器应用程序中，如果调用<code>accept()</code>函数时，并没有客户端请求连接（等待连接队列中也没有等待连接的请求），此时<code>accept()</code>会进入阻塞状态，直到有客户端连接请求到达为止。当有客户端连接请求到达时，<code>accept()</code>函数与远程客户端之间建立连接，<code>accept()</code>函数返回一个新的套接字。这个套接字与<code>socket()</code>函数返回的套接字并不同，<code>socket()</code>函数返回的是服务器的套接字（以服务器为例），而<code>accept()</code>函数返回的套接字连接到调用<code>connect()</code>的客户端，服务器通过该套接字与客户端进行数据交互，例如向客户端发送数据、或从客户端接收数据。</p>
<p>所以，理解<code>accept()</code>函数的关键点在于它会<strong>创建一个新的套接字</strong>，其实这个新的套接字就是与执行<code>connect()</code>（客户端调用<code>connect()</code>向服务器发起连接请求）的客户端之间建立了连接，这个套接字代表了服务器与客户端的一个连接。如果<code>accept()</code>函数执行出错，将会返回<code>-1</code>，并会设置<code>errno</code>以指示错误原因。</p>
<h3 id="4-3-使用实例"><a href="#4-3-使用实例" class="headerlink" title="4.3 使用实例"></a><font size=3>4.3 使用实例</font></h3><p>暂无。</p>
<h2 id="5-connect-函数"><a href="#5-connect-函数" class="headerlink" title="5. connect()函数"></a><font size=3>5. <code>connect()</code>函数</font></h2><h3 id="5-1-函数说明"><a href="#5-1-函数说明" class="headerlink" title="5.1 函数说明"></a><font size=3>5.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 2 connect</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">connect</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">const</span> <span class="keyword">struct</span> sockaddr *addr, <span class="type">socklen_t</span> addrlen)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于客户端应用程序中，客户端调用<code>connect()</code>函数将套接字<code>sockfd</code>与远程服务器进行连接。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sockfd</code>：<code>int</code>类型，表示已经创建的<code>socket</code>描述符。</li>
<li><code>addr</code>：<code>struct sockaddr</code>类型的结构体指针变量，指向一个<code>struct sockaddr</code>类型变量，指定了待连接的服务器的<code>IP</code>地址以及端口号等信息。但是呢，和上边一样，我们一般不使用这个类型，一般会使用<code>struct sockaddr_in</code>类型。</li>
<li><code>addrlen</code>：<code>socklen_t</code>类型，用于指定<code>addr</code>所指向的结构体对应的字节长度，一般由<code>sizeof</code>求得。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败返回<code>-1</code>，并设置<code>errno</code>表示错误类型。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>              <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* connect */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span>         <span class="comment">/* connect */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;strings.h&gt;</span>            <span class="comment">/* bzero exit */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span>          <span class="comment">/* htons htonl */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> port = <span class="number">5002</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">sin</span>;</span></span><br><span class="line">bzero (&amp;<span class="built_in">sin</span>, <span class="keyword">sizeof</span> (<span class="built_in">sin</span>));</span><br><span class="line"><span class="built_in">sin</span>.sin_family = AF_INET;</span><br><span class="line"><span class="built_in">sin</span>.sin_port = htons (port);	<span class="comment">/* 网络字节序的端口号 */</span></span><br><span class="line"><span class="built_in">sin</span>.sin_addr.s_addr = inet_addr (SERV_IP_ADDR); <span class="comment">/* SERV_IP_ADDR是一个自定义宏，表示服务器IP */</span></span><br><span class="line"><span class="keyword">if</span>(connect(fd, (<span class="keyword">struct</span> sockaddr *) &amp;<span class="built_in">sin</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)) &lt; <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line">	perror(<span class="string">&quot;connect&quot;</span>);</span><br><span class="line">	<span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）客户端通过<code>connect()</code>函数请求与服务器建立连接，对于<code>TCP</code>连接来说，调用该函数将发生<code>TCP</code>连接的握手过程，并最终建立一个<code>TCP</code>连接，而对于<code>UDP</code>协议来说，调用这个函数只是在<code>sockfd</code>中记录服务器<code>IP</code>地址与端口号，而不发送任何数据。</p>
<p>（2）对于<code>TCP</code>协议来说，三次握手建立连接的过程就在调用此函数时完成，当连接成功后，也就代表着三次握手也完成了。</p>
<h3 id="5-2-使用实例"><a href="#5-2-使用实例" class="headerlink" title="5.2 使用实例"></a><font size=3>5.2 使用实例</font></h3><p>暂无。</p>
<h2 id="6-断开连接函数"><a href="#6-断开连接函数" class="headerlink" title="6. 断开连接函数"></a><font size=3>6. 断开连接函数</font></h2><h3 id="6-1-close"><a href="#6-1-close" class="headerlink" title="6.1 close()"></a><font size=3>6.1 <code>close()</code></font></h3><h4 id="6-1-1-函数说明"><a href="#6-1-1-函数说明" class="headerlink" title="6.1.1 函数说明"></a><font size=3>6.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 2 close </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">close</span><span class="params">(<span class="type">int</span> fd)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于关闭一个文件描述符，也就是关闭打开的文件，套接字也是一种文件描述符，所以可以使用该函数来关闭。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>fd</code>：<code>int</code>类型，已打开文件的文件描述符。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败返回<code>EOF</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> ret;<span class="comment">/* 保存文件关闭返回值 */</span></span><br><span class="line">ret = close(fd);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）使用该函数会将套接字描述符（或句柄）从内存清除，之后再也不能使用该套接字，也无法使用与数据收发相关的函数。此时客户端和服务器端之间接收和发送数据都无法进行，使用在<code>TCP</code>协议中的话，会自动触发四次握手断开连接的过程。</p>
<p>（2）调用 <code>close()</code>关闭套接字时会向对方发送 <code>FIN</code> 包。<code>FIN</code> 包表示数据传输完毕，计算机收到 <code>FIN</code> 包就知道不会再有数据传送过来了。默认情况下，<code>close()</code> 会立即向网络中发送<code>FIN</code>包，不管输出缓冲区中是否还有数据，也就意味着，调用 <code>close()</code>将丢失输出缓冲区中的数据。</p>
<h4 id="6-1-2-使用实例"><a href="#6-1-2-使用实例" class="headerlink" title="6.1.2 使用实例"></a><font size=3>6.1.2 使用实例</font></h4><p>暂无。</p>
<h3 id="6-2-shutdown"><a href="#6-2-shutdown" class="headerlink" title="6.2 shutdown()"></a><font size=3>6.2 <code>shutdown()</code></font></h3><h4 id="6-2-1-函数说明"><a href="#6-2-1-函数说明" class="headerlink" title="6.2.1 函数说明"></a><font size=3>6.2.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 2 shutdown</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">shutdown</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">int</span> how)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于关闭已经建立的连接，而非直接关闭套接字，该函数允许我们只关闭在某个方向上的数据传输。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sockfd</code>：<code>int</code>类型，表示需要断开连接的<code>socket</code>描述符。</li>
<li><code>how</code>：<code>int</code>类型，表示断开连接的方式。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 how 的取值及含义 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>SHUT_RD</td><td align="left">也就是0，表示断开输入流。套接字无法接收数据（即使输入缓冲区收到数据也被抹去），无法调用输入相关函数。</td></tr>    <tr><td align="center" width=150px>SHUT_WR</td><td align="left">也就是1，表示断开输出流。套接字无法发送数据，但如果输出缓冲区中还有未传输的数据，则将传递到目标主机。</td></tr>    <tr><td align="center" width=150px>SHUT_RDWR</td><td align="left">也就是2，表示同时断开 I/O 流。相当于分两次调用 shutdown()，其中一次以 SHUT_RD 为参数，另一次以 SHUT_WR 为参数。</td></tr></table>
              </div>
            </details>

<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败返回<code>-1</code>，并设置<code>errno</code>表示错误类型。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">shutdown(sockfd, SHUT_RD);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）该函数用于关闭连接，而非关闭套接字，不管调用多少次 <code>shutdown()</code>，套接字依然存在，直到调用 <code>close()</code> 将套接字从内存清除。</p>
<p>（2）调用 <code>shutdown() </code>关闭输出流时，会向对方发送 <code>FIN</code> 包，表示告诉对方数据传输完毕，不会再有数据了。默认情况下，<code>shutdown()</code> 会等输出缓冲区中的数据传输完毕再发送<code>FIN</code>包，这也就意味着，使用 <code>shutdown()</code> 不会丢失缓冲区的数据。</p>
<h4 id="6-2-2-使用实例"><a href="#6-2-2-使用实例" class="headerlink" title="6.2.2 使用实例"></a><font size=3>6.2.2 使用实例</font></h4><p>暂无。</p>
<h1 id="三、IP地址转换"><a href="#三、IP地址转换" class="headerlink" title="三、IP地址转换"></a><font size=3>三、<code>IP</code>地址转换</font></h1><p>上边我们已经了解了几个<code>socket</code>函数的使用方法，里边绑定<code>IP</code>的时候用到了一些转换函数，这些是用于转换<code>IP</code>地址以及字节序的，关于字节序的问题，前边其实已经了解过了。对于<code>IP</code>地址，我们定义的时候或者输入的时候一般都是点分十进制表示的字符串形式，但是函数使用的却是整数形式的<code>IP</code>地址，这样我们就需要<code>IP</code>转换为符合函数使用要求的形式。</p>
<h2 id="1-字节序转换"><a href="#1-字节序转换" class="headerlink" title="1. 字节序转换"></a><font size=3>1. 字节序转换</font></h2><p>字节序的转换函数有四个，分别是：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">uint32_t</span> <span class="title function_">htonl</span><span class="params">(<span class="type">uint32_t</span> hostlong)</span>;  <span class="comment">/* 主机字节序---&gt;网络字节序 */</span></span><br><span class="line"><span class="type">uint16_t</span> <span class="title function_">htons</span><span class="params">(<span class="type">uint16_t</span> hostshort)</span>; <span class="comment">/* 主机字节序---&gt;网络字节序 */</span></span><br><span class="line"><span class="type">uint32_t</span> <span class="title function_">ntohl</span><span class="params">(<span class="type">uint32_t</span> netlong)</span>;   <span class="comment">/* 网络字节序---&gt;主机字节序 */</span></span><br><span class="line"><span class="type">uint16_t</span> <span class="title function_">ntohs</span><span class="params">(<span class="type">uint16_t</span> netshort)</span>;  <span class="comment">/* 网络字节序---&gt;主机字节序 */</span></span><br></pre></td></tr></table></figure>

<p>【命名说明】</p>
<ul>
<li><code>h</code>为<code>host</code>，表示主机字节顺序；</li>
<li><code>n</code>为<code>net</code>，表示网络字节顺序；</li>
<li><code>l</code>表示无符号整型数据；</li>
<li><code>s</code>表示无符号短整型数据。</li>
</ul>
<h3 id="1-1-htonl"><a href="#1-1-htonl" class="headerlink" title="1.1 htonl()"></a><font size=3>1.1 <code>htonl()</code></font></h3><h4 id="1-1-1-函数说明"><a href="#1-1-1-函数说明" class="headerlink" title="1.1.1 函数说明"></a><font size=3>1.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man htonl</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">uint32_t</span> <span class="title function_">htonl</span><span class="params">(<span class="type">uint32_t</span> hostlong)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数将无符号整型数据<code>hostlong</code>从主机字节顺序转换成网络字节顺序（<code>32</code>位）。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>hostlong</code>：<code>uint32_t</code>类型，表示需要转换的无符号整型数据。</li>
</ul>
<p><strong>【返回值】</strong><code>uint32_t</code>类型，返回转换后的数据。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">htonl(hostlong);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="1-1-2-使用实例"><a href="#1-1-2-使用实例" class="headerlink" title="1.1.2 使用实例"></a><font size=3>1.1.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">uint32_t</span> IP = <span class="number">0x12345678</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;sizeof(uint32_t)=%ld\n&quot;</span>, <span class="keyword">sizeof</span>(<span class="type">uint32_t</span>));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;before=%#x, after=%#x\n&quot;</span>, IP, htonl(IP));</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sizeof(uint32_t)=4</span><br><span class="line">before=0x12345678, after=0x78563412</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="1-2-htons"><a href="#1-2-htons" class="headerlink" title="1.2 htons()"></a><font size=3>1.2 <code>htons()</code></font></h3><h4 id="1-2-1-函数说明"><a href="#1-2-1-函数说明" class="headerlink" title="1.2.1 函数说明"></a><font size=3>1.2.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man htons</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">uint16_t</span> <span class="title function_">htons</span><span class="params">(<span class="type">uint16_t</span> hostshort)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数将无符号短整型数据<code>hostshort</code>从主机字节顺序转换为网络字节顺序。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>hostshort</code>：<code>uint16_t</code>类型，表示需要转换的无符号短整型数据。</li>
</ul>
<p><strong>【返回值】</strong><code>uint16_t</code>类型，返回转换后的数据。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">htons(hostshort);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="1-2-2-使用实例"><a href="#1-2-2-使用实例" class="headerlink" title="1.2.2 使用实例"></a><font size=3>1.2.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">uint16_t</span> IP = <span class="number">0x1234</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;sizeof(uint16_t)=%ld\n&quot;</span>, <span class="keyword">sizeof</span>(<span class="type">uint16_t</span>));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;before=%#x, after=%#x\n&quot;</span>, IP, htons(IP));</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sizeof(uint16_t)=2</span><br><span class="line">before=0x1234, after=0x3412</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="1-3-ntohl"><a href="#1-3-ntohl" class="headerlink" title="1.3 ntohl()"></a><font size=3>1.3 <code>ntohl()</code></font></h3><h4 id="1-3-1-函数说明"><a href="#1-3-1-函数说明" class="headerlink" title="1.3.1 函数说明"></a><font size=3>1.3.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man ntohl</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">uint32_t</span> <span class="title function_">ntohl</span><span class="params">(<span class="type">uint32_t</span> netlong)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数将无符号整型数据<code>netlong</code>从网络字节顺序转换为主机字节顺序。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>netlong</code>：<code>uint32_t</code>类型，表示需要转换的无符号整型数据。</li>
</ul>
<p><strong>【返回值】</strong><code>uint32_t</code>类型，返回转换后的数据。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">ntohl(netlong);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="1-3-2-使用实例"><a href="#1-3-2-使用实例" class="headerlink" title="1.3.2 使用实例"></a><font size=3>1.3.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">uint32_t</span> IP = <span class="number">0x78563412</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;sizeof(uint32_t)=%ld\n&quot;</span>, <span class="keyword">sizeof</span>(<span class="type">uint32_t</span>));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;before=%#x, after=%#x\n&quot;</span>, IP, ntohl(IP));</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sizeof(uint32_t)=4</span><br><span class="line">before=0x78563412, after=0x12345678</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="1-4-ntohs"><a href="#1-4-ntohs" class="headerlink" title="1.4 ntohs()"></a><font size=3>1.4 <code>ntohs()</code></font></h3><h4 id="1-4-1-函数说明"><a href="#1-4-1-函数说明" class="headerlink" title="1.4.1 函数说明"></a><font size=3>1.4.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man ntohs</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">uint16_t</span> <span class="title function_">ntohs</span><span class="params">(<span class="type">uint16_t</span> netshort)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数将无符号短整型数据<code>netshort</code>从网络字节顺序转换为主机字节顺序。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>netshort</code>：<code>uint16_t</code>类型，表示需要转换的无符号短整型数据。</li>
</ul>
<p><strong>【返回值】</strong><code>uint16_t</code>类型，返回转换后的数据。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">ntohs(netshort);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="1-4-2-使用实例"><a href="#1-4-2-使用实例" class="headerlink" title="1.4.2 使用实例"></a><font size=3>1.4.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">uint16_t</span> IP = <span class="number">0x3412</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;sizeof(uint16_t)=%ld\n&quot;</span>, <span class="keyword">sizeof</span>(<span class="type">uint16_t</span>));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;before=%#x, after=%#x\n&quot;</span>, IP, ntohs(IP));</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sizeof(uint16_t)=2</span><br><span class="line">before=0x3412, after=0x1234</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h2 id="2-IP字符串转换"><a href="#2-IP字符串转换" class="headerlink" title="2.IP字符串转换"></a><font size=3>2.<code>IP</code>字符串转换</font></h2><p>点分十进制字符串和二进制地址之间的转换函数主要有： <code>inet_aton</code>、 <code>inet_addr</code>、<code>inet_ntoa</code>、<code> inet_ntop</code>、<code>inet_pton</code> 这五个，在我们的应用程序中使用它们需要包含头文件<code>&lt;sys/socket.h&gt;</code>、 <code>&lt;arpa/inet.h&gt;</code>以及<code>&lt;netinet/in.h&gt;</code>。  </p>
<p>说明：</p>
<p> <code>inet_aton</code>、 <code>inet_addr</code>、<code>inet_ntoa</code>这些函数可将一个 IP 地址在点分十进制表示形式和二进制表示形式之间进行转换，这些函数已经废弃了， 基本不用这些函数了，但是在一些旧的代码中可能还会看到这些函数。完成此类转换工作我们应该使用这几个：<code> inet_ntop</code>、<code>inet_pton</code> 。</p>
<h3 id="2-1inet-aton-函数"><a href="#2-1inet-aton-函数" class="headerlink" title="2.1inet_aton()函数"></a><font size=3>2.1<code>inet_aton()</code>函数</font></h3><h4 id="2-1-1-函数说明"><a href="#2-1-1-函数说明" class="headerlink" title="2.1.1 函数说明"></a><font size=3>2.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man inet_aton</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">inet_aton</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *cp, <span class="keyword">struct</span> in_addr *inp)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数将<code>Internet</code>主机地址<code>cp</code>从<code>IPv4</code>的点号表示法转换成二进制形式(以<strong>网络字节顺序</strong>)，并将其存储在<code>inp</code>指向的结构中。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>cp</code>：<code>char</code>类型指针变量，指向存放<code>IP</code>地址的内存空间。</li>
<li><code>inp</code>：<code>struct in_addr</code>类型，存放转换后的<code>IP</code>地址。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 struct in_addr 成员 </summary>
              <div class='content'>
              <p>该结构体定义在<code>netinet/in.h</code>中：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="type">uint32_t</span> <span class="type">in_addr_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">in_addr_t</span> s_addr;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>1</code>，失败或者字符串无效返回<code>0</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">char</span> *cp = <span class="string">&quot;192.168.0.1&quot;</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">addr</span>;</span></span><br><span class="line"><span class="type">int</span> ret = <span class="number">-1</span>;</span><br><span class="line">ret = inet_aton(cp, &amp;addr);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="2-1-2-使用实例"><a href="#2-1-2-使用实例" class="headerlink" title="2.1.2 使用实例"></a><font size=3>2.1.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span> </span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> arc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">char</span> *cp = <span class="string">&quot;192.168.0.1&quot;</span>;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">addr</span>;</span></span><br><span class="line">	<span class="type">int</span> ret = <span class="number">-1</span>;</span><br><span class="line">	ret = inet_aton(cp, &amp;addr);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;ret = %d\n&quot;</span>, ret);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;cp = %s, addr.s_addr = %#x\n&quot;</span>, cp, addr.s_addr);</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ret = 1</span><br><span class="line">cp = 192.168.0.1, addr.s_addr = 0x100a8c0</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="2-2inet-addr-函数"><a href="#2-2inet-addr-函数" class="headerlink" title="2.2inet_addr()函数"></a><font size=3>2.2<code>inet_addr()</code>函数</font></h3><h4 id="2-2-1-函数说明"><a href="#2-2-1-函数说明" class="headerlink" title="2.2.1 函数说明"></a><font size=3>2.2.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man inet_addr</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">in_addr_t</span> <span class="title function_">inet_addr</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *cp)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于将<code>Internet</code>主机地址<code>cp</code>从<code>IPv4</code>的点号表示法转换成<strong>网络字节顺序</strong>的二进制数据。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>cp</code>：<code>char</code>类型指针变量，指向存放<code>IP</code>地址的内存空间。</li>
</ul>
<p><strong>【返回值】</strong><code>in_addr_t</code>类型，成功返回转换后的<code>IP</code>地址，失败或者字符串无效返回<code>INADDR_NONE  </code>，这一般是<code>-1</code>，需要注意的是这是有问题的，因为<code>-1</code>在<code>in_addr_t</code>类型下在计算机中为<code>0xffff ffff</code>（补码），这其实是一个有效的地址(<code>255.255.255.255</code>)。</p>
<details class="folding-tag" blue><summary> 点击查看 in_addr_t 类型 </summary>
              <div class='content'>
              <p>该类型定义在<code>netinet/in.h</code>中：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="type">uint32_t</span> <span class="type">in_addr_t</span>;</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">char</span> *cp = <span class="string">&quot;192.168.0.1&quot;</span>;</span><br><span class="line"><span class="type">in_addr_t</span> ret;</span><br><span class="line">ret = inet_addr(cp);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）内部包含了字节序的转换，默认是网络字节序的模式。</p>
<p>（2）仅适用于<code>IPV4</code>。</p>
<p>（3）当出错时，返回<code>-1</code>，此函数不能用于<code>255.255.255.255</code>的转换。</p>
<h4 id="2-2-2-使用实例"><a href="#2-2-2-使用实例" class="headerlink" title="2.2.2 使用实例"></a><font size=3>2.2.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> arc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">char</span> *cp1 = <span class="string">&quot;192.168.0.1&quot;</span>;</span><br><span class="line">	<span class="type">char</span> *cp2 = <span class="string">&quot;255.255.255.255&quot;</span>;</span><br><span class="line">	<span class="type">char</span> *cp3 = <span class="string">&quot;n&quot;</span>;</span><br><span class="line">	<span class="type">in_addr_t</span> ret1, ret2, ret3;</span><br><span class="line">	ret1 = inet_addr(cp1);</span><br><span class="line">	ret2 = inet_addr(cp2);</span><br><span class="line">	ret3 = inet_addr(cp2);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;cp1 = %s, ret1 = %#x\n&quot;</span>, cp1, ret1);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;cp2 = %s, ret2 = %#x\n&quot;</span>, cp2, ret2);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;cp3 = %s, ret3 = %#x\n&quot;</span>, cp3, ret3);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cp1 = 192.168.0.1, ret1 = 0x100a8c0</span><br><span class="line">cp2 = 255.255.255.255, ret2 = 0xffffffff</span><br><span class="line">cp3 = n, ret3 = 0xffffffff</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="2-3inet-ntoa-函数"><a href="#2-3inet-ntoa-函数" class="headerlink" title="2.3inet_ntoa()函数"></a><font size=3>2.3<code>inet_ntoa()</code>函数</font></h3><h4 id="2-3-1-函数说明"><a href="#2-3-1-函数说明" class="headerlink" title="2.3.1 函数说明"></a><font size=3>2.3.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man inet_ntoa</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">char</span> *<span class="title function_">inet_ntoa</span><span class="params">(<span class="keyword">struct</span> in_addr in)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数将以网络字节顺序给出的<code>Internet</code>主机二进制地址转换为<code>IPv4</code>点分十进制格式的字符串。该字符串在静态分配的缓冲区中返回，后续调用将覆盖该缓冲区。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>in</code>：<code>struct in_addr</code>类型，内部只有一个成员<code>s_addr</code>，表示以网络字节顺序给出的<code>Internet</code>主机二进制地址。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 struct in_addr 成员 </summary>
              <div class='content'>
              <p>该结构体定义在<code>netinet/in.h</code>中：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="type">uint32_t</span> <span class="type">in_addr_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">in_addr_t</span> s_addr;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p><strong>【返回值】</strong><code>char</code>类型指针变量，成功返回转换后的点分十进制<code>IPv4</code>地址，否则返回<code>NULL</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">addr</span>;</span></span><br><span class="line">addr.s_addr = <span class="number">0x12345678</span></span><br><span class="line"><span class="type">char</span> *p = <span class="literal">NULL</span>;</span><br><span class="line">p = inet_ntoa(addr);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;p = %s\n&quot;</span>, p);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="2-3-2-使用实例"><a href="#2-3-2-使用实例" class="headerlink" title="2.3.2 使用实例"></a><font size=3>2.3.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> arc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">char</span> *cp = <span class="string">&quot;192.168.0.1&quot;</span>;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">addr</span>;</span></span><br><span class="line">	<span class="type">char</span> *p = <span class="literal">NULL</span>;</span><br><span class="line">	inet_aton(cp, &amp;addr);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;cp = %s, addr.s_addr = %#x\n&quot;</span>, cp, addr.s_addr);</span><br><span class="line">	p = inet_ntoa(addr);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;p = %s\n&quot;</span>, p);</span><br><span class="line">	</span><br><span class="line">	addr.s_addr = <span class="number">0x12345678</span>;</span><br><span class="line">	p = inet_ntoa(addr);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;p = %s\n&quot;</span>, p);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cp = 192.168.0.1, addr.s_addr = 0x100a8c0</span><br><span class="line">p = 192.168.0.1</span><br><span class="line">p = 120.86.52.18</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="2-4inet-pton-函数"><a href="#2-4inet-pton-函数" class="headerlink" title="2.4inet_pton()函数"></a><font size=3>2.4<code>inet_pton()</code>函数</font></h3><h4 id="2-4-1-函数说明"><a href="#2-4-1-函数说明" class="headerlink" title="2.4.1 函数说明"></a><font size=3>2.4.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man inet_pton</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">inet_pton</span><span class="params">(<span class="type">int</span> af, <span class="type">const</span> <span class="type">char</span> *src, <span class="type">void</span> *dst)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数将点分十进制表示的字符串形式<code>IP</code>转换成网络字节序的二进制<code>IPv4</code>或<code>IPv6</code>地址。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>af</code>：<code>int</code>类型，协议族，这里必须是<code>AF_INET</code>或<code>AF_INET6</code>，其中<code>AF_INET</code>表示目标地址为<code>IPv4</code>地址，<code>AF_INET6</code>表示目标地址为<code>IPv6</code>地址。</li>
<li><code>src</code>：<code>char</code>类型指针变量，指向需要转换的字符串形式的<code>IP</code>地址。</li>
<li><code>dst</code>：<code>void</code>类型指针变量，转换后得到的地址存放在参数<code>dst</code>所指向的对象中。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看参数类型说明 </summary>
              <div class='content'>
              <p>当参数<code>af</code>被指定为<code>AF_INET</code>，则参数<code>dst</code>所指对象应该是一个<code>struct in_addr</code>结构体的对象；如果参数<code>af</code>被指定为<code>AF_INET6</code>，则参数<code>dst</code>所指对象应该是一个<code>struct in6_addr</code>结构体的对象。这两个结构体都定义在<code>netinet/in.h</code>文件中：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Internet address.  */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">uint32_t</span> <span class="type">in_addr_t</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">in_addr_t</span> s_addr;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* IPv6 address */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in6_addr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="class"><span class="keyword">union</span></span></span><br><span class="line"><span class="class">	&#123;</span></span><br><span class="line">		<span class="type">uint8_t</span> __u6_addr8[<span class="number">16</span>];</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined __USE_MISC || defined __USE_GNU</span></span><br><span class="line">		<span class="type">uint16_t</span> __u6_addr16[<span class="number">8</span>];</span><br><span class="line">		<span class="type">uint32_t</span> __u6_addr32[<span class="number">4</span>];</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">	&#125; __in6_u;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> s6_addr                 __in6_u.__u6_addr8</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined __USE_MISC || defined __USE_GNU</span></span><br><span class="line"><span class="meta"># <span class="keyword">define</span> s6_addr16              __in6_u.__u6_addr16</span></span><br><span class="line"><span class="meta"># <span class="keyword">define</span> s6_addr32              __in6_u.__u6_addr32</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>1</code>（已成功转换）。如果<code>src</code>不包含表示指定地址族中有效网络地址的字符串，则返回<code>0</code>；如果<code>af</code>不包含有效的地址族，则返回<code>-1</code>并将<code>errno</code>设置为<code>EAFNOSUPPORT</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">char</span> *src = <span class="string">&quot;192.168.0.1&quot;</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">addr</span>;</span></span><br><span class="line">inet_pton(AF_INET, src, (<span class="type">void</span> *)&amp;addr.s_addr);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）内部包含了字节序的转换，默认是网络字节序的模式。</p>
<p>（2）适用于<code>IPV4</code>和<code>IPv6</code>。</p>
<p>（3）此函数可以用于<code>255.255.255.255</code>的转换。</p>
<p>（4）注意<code>src</code>为一个字符串，若是想要填充<code>INADDR_ANY</code>以达到保定所有<code>IP</code>的目的，最好还是使用其他的函数比较好，这是因为<code>INADDR_ANY</code>其实是一个<code>in_addr_t</code>类型，它直接就是一个二进制形式的<code>IPv4</code>地址。</p>
<h4 id="2-4-2-使用实例"><a href="#2-4-2-使用实例" class="headerlink" title="2.4.2 使用实例"></a><font size=3>2.4.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> arc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">char</span> *src1 = <span class="string">&quot;192.168.0.1&quot;</span>;</span><br><span class="line">	<span class="type">char</span> *src2 = <span class="string">&quot;255.255.255.255&quot;</span>;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">addr1</span>, <span class="title">addr2</span>;</span></span><br><span class="line">	<span class="keyword">if</span>(inet_pton (AF_INET, src1, (<span class="type">void</span> *)&amp;addr1.s_addr) != <span class="number">1</span> ||</span><br><span class="line">	   inet_pton (AF_INET, src2, (<span class="type">void</span> *)&amp;addr2.s_addr) != <span class="number">1</span> )</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;inet_pton&quot;</span>);</span><br><span class="line">		<span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;src1 = %s, addr1.s_addr = %#x\n&quot;</span>, src1, addr1.s_addr);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;src2 = %s, addr2.s_addr = %#x\n&quot;</span>, src2, addr2.s_addr);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">src1 = 192.168.0.1, addr1.s_addr = 0x100a8c0</span><br><span class="line">src2 = 255.255.255.255, addr2.s_addr = 0xffffffff</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="2-5inet-ntop-函数"><a href="#2-5inet-ntop-函数" class="headerlink" title="2.5inet_ntop()函数"></a><font size=3>2.5<code>inet_ntop()</code>函数</font></h3><h4 id="2-5-1-函数说明"><a href="#2-5-1-函数说明" class="headerlink" title="2.5.1 函数说明"></a><font size=3>2.5.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man inet_ntop</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">const</span> <span class="type">char</span> *<span class="title function_">inet_ntop</span><span class="params">(<span class="type">int</span> af, <span class="type">const</span> <span class="type">void</span> *src, <span class="type">char</span> *dst, <span class="type">socklen_t</span> size)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数将网络字节序的二进制<code>IPv4</code>或<code>IPv6</code>地址变成本地的字符串形式的<code>IP</code>地址。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>af</code>：<code>int</code>类型，协议族，这里必须是<code>AF_INET</code>或<code>AF_INET6</code>，其中<code>AF_INET</code>表示目标地址为<code>IPv4</code>地址，<code>AF_INET6</code>表示目标地址为<code>IPv6</code>地址。</li>
<li><code>src</code>：<code>void</code>类型指针变量，需要转换的网络字节序的二进制<code>IPv4</code>或<code>IPv6</code>地址存放在参数<code>src</code>所指向的对象中。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看参数类型说明 </summary>
              <div class='content'>
              <p>当参数<code>af</code>被指定为<code>AF_INET</code>，则参数<code>src</code>所指对象应该是一个<code>struct in_addr</code>结构体的对象；如果参数<code>af</code>被指定为<code>AF_INET6</code>，则参数<code>src</code>所指对象应该是一个<code>struct in6_addr</code>结构体的对象。这两个结构体都定义在<code>netinet/in.h</code>文件中：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Internet address.  */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">uint32_t</span> <span class="type">in_addr_t</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">in_addr_t</span> s_addr;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* IPv6 address */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in6_addr</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="class"><span class="keyword">union</span></span></span><br><span class="line"><span class="class">	&#123;</span></span><br><span class="line">		<span class="type">uint8_t</span> __u6_addr8[<span class="number">16</span>];</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined __USE_MISC || defined __USE_GNU</span></span><br><span class="line">		<span class="type">uint16_t</span> __u6_addr16[<span class="number">8</span>];</span><br><span class="line">		<span class="type">uint32_t</span> __u6_addr32[<span class="number">4</span>];</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">	&#125; __in6_u;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> s6_addr                 __in6_u.__u6_addr8</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined __USE_MISC || defined __USE_GNU</span></span><br><span class="line"><span class="meta"># <span class="keyword">define</span> s6_addr16              __in6_u.__u6_addr16</span></span><br><span class="line"><span class="meta"># <span class="keyword">define</span> s6_addr32              __in6_u.__u6_addr32</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<ul>
<li><code>dst</code>：<code>char</code>类型指针变量，转换完成的字符串存放在参数<code>dts</code>所指的缓冲区中。</li>
<li><code>size</code>：<code>socklen_t</code>类型，指定了<code>dst</code>所指向缓冲区的大小，也就是存放转换完成的字符串的内存大小。</li>
</ul>
<p><strong>【返回值】</strong><code>char</code>类型指针变量，成功返回转换完成后所得到字符串的首地址。失败返回<code>NULL</code>并将<code>errno</code>设置表示错误类型。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">addr</span>;</span></span><br><span class="line"><span class="type">char</span> buf1[<span class="number">20</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">inet_ntop(AF_INET, (<span class="type">void</span> *)&amp;addr.s_addr, buf, <span class="keyword">sizeof</span>(buf));</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）适用于<code>IPV4</code>和<code>IPv6</code>。</p>
<p>（2）此函数可以用于<code>255.255.255.255</code>的转换。</p>
<h4 id="2-5-2-使用实例"><a href="#2-5-2-使用实例" class="headerlink" title="2.5.2 使用实例"></a><font size=3>2.5.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> arc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">char</span> *src1 = <span class="string">&quot;192.168.0.1&quot;</span>;</span><br><span class="line">	<span class="type">char</span> *src2 = <span class="string">&quot;255.255.255.255&quot;</span>;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">in_addr</span> <span class="title">addr1</span>, <span class="title">addr2</span>;</span></span><br><span class="line">	<span class="type">char</span> buf1[<span class="number">20</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">	<span class="type">char</span> buf2[<span class="number">20</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">	<span class="keyword">if</span>(inet_pton (AF_INET, src1, (<span class="type">void</span> *)&amp;addr1.s_addr) != <span class="number">1</span> ||</span><br><span class="line">	   inet_pton (AF_INET, src2, (<span class="type">void</span> *)&amp;addr2.s_addr) != <span class="number">1</span> )</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;inet_pton&quot;</span>);</span><br><span class="line">		<span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;src1 = %s, addr1.s_addr = %#x\n&quot;</span>, src1, addr1.s_addr);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;src2 = %s, addr2.s_addr = %#x\n&quot;</span>, src2, addr2.s_addr);</span><br><span class="line">	</span><br><span class="line">	inet_ntop(AF_INET, (<span class="type">void</span> *)&amp;addr1.s_addr, buf1, <span class="keyword">sizeof</span>(buf1));</span><br><span class="line">	inet_ntop(AF_INET, (<span class="type">void</span> *)&amp;addr2.s_addr, buf2, <span class="keyword">sizeof</span>(buf2));</span><br><span class="line">	</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;src1 = %s, buf1 = %s\n&quot;</span>, src1, buf1);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;src2 = %s, buf2 = %s\n&quot;</span>, src2, buf2);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">src1 = 192.168.0.1, addr1.s_addr = 0x100a8c0</span><br><span class="line">src2 = 255.255.255.255, addr2.s_addr = 0xffffffff</span><br><span class="line">src1 = 192.168.0.1, buf1 = 192.168.0.1</span><br><span class="line">src2 = 255.255.255.255, buf2 = 255.255.255.255</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h1 id="四、数据传输"><a href="#四、数据传输" class="headerlink" title="四、数据传输"></a><font size=3>四、数据传输</font></h1><p>上边我们已经了解了建立一个网络通信的连接所需的相关函数，一旦客户端和服务器端建立好连接后，就可以通过套接字进行数据的传输了。对于客户端使用<code>socket()</code>返回的套接字描述符，而对于服务器来说，需要使用<code>accept()</code>返回的套接字描述符，注意这里服务器使用的并不是程序一开始的时候创建的那个<code>socket</code>描述符，原来的那个会继续用于监听。</p>
<h2 id="1-read-write"><a href="#1-read-write" class="headerlink" title="1. read()/write()"></a><font size=3>1. <code>read()/write()</code></font></h2><p><code>read()</code>和<code>write()</code>这两个函数一般用于面向连接的<code>socket</code>上进行数据传输。也就是说这两个函数一般用于<code>TCP</code>协议编程中。</p>
<h3 id="1-1-read"><a href="#1-1-read" class="headerlink" title="1.1 read()"></a><font size=3>1.1 <code>read()</code></font></h3><h4 id="1-1-1-函数说明-1"><a href="#1-1-1-函数说明-1" class="headerlink" title="1.1.1 函数说明"></a><font size=3>1.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 2 read</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">read</span><span class="params">(<span class="type">int</span> fd, <span class="type">void</span> *buf, <span class="type">size_t</span> count)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数可以从文件中读取数据。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>fd</code>：<code>int</code>类型，表示已打开的文件描述符。</li>
<li><code>buf</code>：<code>void</code>类型指针变量，表示接收数据的缓冲区。</li>
<li><code>count</code>：<code>size_t</code>类型，表示需要读取的字节数，不应超过<code>buf</code>。</li>
</ul>
<p><strong>【返回值】</strong><code>ssize_t</code>类型（表示有符号的<code>size_t</code>），成功时返回实际读取的字节数；出错时返回<code>EOF</code>，读到文件末尾时返回<code>0</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> socket_fd = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>); <span class="comment">/* 创建套接字 */</span></span><br><span class="line"><span class="type">char</span> buff[<span class="number">32</span>]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line">ret = read(fd, buff, <span class="number">32</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>该函数可以在很多场景下用于读取数据，在网络编程中，套接字创建好直接会有一个打开的文件描述符，所以就不需要再使用其他的相关函数打开一个文件描述符了。</p>
<h4 id="1-1-2-使用实例-1"><a href="#1-1-2-使用实例-1" class="headerlink" title="1.1.2 使用实例"></a><font size=3>1.1.2 使用实例</font></h4><p>暂无</p>
<h3 id="1-2-write"><a href="#1-2-write" class="headerlink" title="1.2 write()"></a><font size=3>1.2 <code>write()</code></font></h3><h4 id="1-2-1-函数说明-1"><a href="#1-2-1-函数说明-1" class="headerlink" title="1.2.1 函数说明"></a><font size=3>1.2.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 2 write</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">write</span><span class="params">(<span class="type">int</span> fd, <span class="type">const</span> <span class="type">void</span> *buf, <span class="type">size_t</span> count)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于向文件写入数据。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><p><code>fd</code>：<code>int</code>类型，表示已打开的文件描述符。</p>
</li>
<li><p><code>buf</code>：<code>void</code>类型指针变量，表示要写入文件的数据的缓冲区。</p>
</li>
<li><p><code>count</code>：<code>size_t</code>类型，表示需要写入的字节数，不应超过<code>buf</code>。</p>
</li>
</ul>
<p><strong>【返回值】</strong><code>ssize_t</code>类型，成功时返回实际写入的字节数；出错时返回<code>EOF</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> socket_fd = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>); <span class="comment">/* 创建套接字 */</span></span><br><span class="line"><span class="type">char</span> buff[<span class="number">32</span>]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line">ret = write(fd, buff, <span class="number">32</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>该函数可以在很多场景下用于写入数据，在网络编程中，套接字创建好直接会有一个打开的文件描述符，所以就不需要再使用其他的相关函数打开一个文件描述符了。</p>
<h4 id="1-2-2-使用实例-1"><a href="#1-2-2-使用实例-1" class="headerlink" title="1.2.2 使用实例"></a><font size=3>1.2.2 使用实例</font></h4><p>暂无</p>
<h2 id="2-recv-send"><a href="#2-recv-send" class="headerlink" title="2.recv()/send()"></a><font size=3>2.<code>recv()/send()</code></font></h2><p><code>recv()</code>和<code>send()</code>这两个函数一般用于面向连接的<code>socket</code>上进行数据传输。也就是说这两个函数一般用于<code>TCP</code>协议编程中。</p>
<h3 id="2-1-recv"><a href="#2-1-recv" class="headerlink" title="2.1 recv()"></a><font size=3>2.1 <code>recv()</code></font></h3><h4 id="2-1-1-函数说明-1"><a href="#2-1-1-函数说明-1" class="headerlink" title="2.1.1 函数说明"></a><font size=3>2.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 2 recv</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">recv</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">void</span> *buf, <span class="type">size_t</span> len, <span class="type">int</span> flags)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数可以用于接收来自<code>socket</code>套接字的数据。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sockfd</code>：<code>int</code>类型，表示已打开的<code>socket</code>描述符。</li>
<li><code>buf</code>：<code>void</code>类型指针变量，表示接收数据的缓冲区。</li>
<li><code>len</code>：<code>size_t</code>类型，表示需要读取的字节数，不应超过<code>buf</code>。</li>
<li><code>flags</code>：<code>int</code>类型，指定一些标志用于控制如何接收数据。一般来说，这里我们选择<code>0</code>，这样这个函数就跟<code>read()</code>一样了。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看flags常见可取值及含义 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>标志</td><td align="center">描述</td></tr>    <tr><td align="center" width=150px>MSG_CMSG_CLOEXEC</td><td align="left">为UNIX域套接字上接收的文件描述符设置执行时关闭标志</td></tr>    <tr><td align="center" width=150px>MSG_DONTWAIT</td><td align="left">启动非阻塞操作（相当于O_NONBLOCK）</td></tr>    <tr><td align="center" width=150px>MSG_ERRQUEUE</td><td align="left">接收错误信息作为辅助数据</td></tr>    <tr><td align="center" width=150px>MSG_OOB</td><td align="left">如果协议支持，获取带外数据</td></tr>    <tr><td align="center" width=150px>MSG_PEEK</td><td align="left">返回数据包内容而不真正取走数据包</td></tr>    <tr><td align="center" width=150px>MSG_TRUNC</td><td align="left">即使数据包被截断，也返回数据包的长度</td></tr>    <tr><td align="center" width=150px>MSG_WAITALL</td><td align="left">等待直到所有的数据可用（仅SOCK_STREAM）</td></tr></table>当指定`MSG_PEEK`标志时，可以查看下一个要读取的数据但不真正取走它，当再次调用`read()`或`recv()`函数时，会返回刚才查看的数据。对于`SOCK_STREAM`类型套接字，接收的数据可以比指定的字节大小少。`MSG_WAITALL`标志会阻止这种行为，直到所请求的数据全部返回，`recv()`函数才会返回。对于`SOCK_DGRAM`和`SOCK_SEQPACKET`套接字，`MSG_WAITALL`标志并不会改变什么行为，因为这些基于报文的套接字类型一次读取就返回整个报文。
              </div>
            </details>

<p><strong>【返回值】</strong><code>ssize_t</code>类型（表示有符号的<code>size_t</code>），成功时返回实际读取的字节数；出错时返回<code>-1</code>，并设置<code>errno</code>表示错误类型。如果发送者已经调用<code>shutdown</code>来结束传输，或者网络协议支持按默认的顺序关闭并且发送端已经关闭，那么当所有的数据接收完毕后，<code>recv()</code>会返回<code>0</code>(传统的“文件结束”返回)。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> socket_fd = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>); <span class="comment">/* 创建套接字 */</span></span><br><span class="line"><span class="type">char</span> recvbuf[<span class="number">32</span>]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">int</span> recvbuflen = <span class="number">32</span>;</span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line">ret = recv(socket_fd, recvbuf, recvbuflen, <span class="number">0</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="2-1-2-使用实例-1"><a href="#2-1-2-使用实例-1" class="headerlink" title="2.1.2 使用实例"></a><font size=3>2.1.2 使用实例</font></h4><p>暂无</p>
<h3 id="2-2-send"><a href="#2-2-send" class="headerlink" title="2.2 send()"></a><font size=3>2.2 <code>send()</code></font></h3><h4 id="2-2-1-函数说明-1"><a href="#2-2-1-函数说明-1" class="headerlink" title="2.2.1 函数说明"></a><font size=3>2.2.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 2 send</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">send</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">const</span> <span class="type">void</span> *buf, <span class="type">size_t</span> len, <span class="type">int</span> flags)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数可以用于向<code>socket</code>套接字发送数据。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sockfd</code>：<code>int</code>类型，表示已打开的<code>socket</code>描述符。</li>
<li><code>buf</code>：<code>void</code>类型指针变量，表示要发送数据的缓冲区。</li>
<li><code>len</code>：<code>size_t</code>类型，表示需要发送的数据的字节数，不应超过<code>buf</code>。</li>
<li><code>flags</code>：<code>int</code>类型，指定一些标志用于控制如何发送数据，这也是该函数与<code>write()</code>函数的唯一区别。一般来说，这里我们选择<code>0</code>，这样这个函数就跟<code>write()</code>一样了。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看flags常见可取值及含义 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>标志</td><td align="center">描述</td></tr>    <tr><td align="center" width=150px>MSG_CONFIRM</td><td align="left">提供链路层反馈以保持地址映射有效</td></tr>    <tr><td align="center" width=150px>MSG_DONTROUTE</td><td align="left">勿将数据包路由出本地网络</td></tr>    <tr><td align="center" width=150px>MSG_DONTWAIT </td><td align="left">允许非阻塞操作（等价于使用 O_NONBLOCK）</td></tr>    <tr><td align="center" width=150px>MSG_EOR</td><td align="left">如果协议支持，标志记录结束</td></tr>    <tr><td align="center" width=150px>MSG_MORE</td><td align="left">延迟发送数据包允许写更多数据</td></tr>    <tr><td align="center" width=150px>MSG_NOSIGNAL</td><td align="left">在写无连接的套接字时不产生 SIGPIPE 信号</td></tr>    <tr><td align="center" width=150px>MSG_OOB</td><td align="left">如果协议支持，发送带外数据</td></tr></table>
              </div>
            </details>

<p><strong>【返回值】</strong><code>ssize_t</code>类型（表示有符号的<code>size_t</code>），成功时返回发送的字节数；出错时返回<code>-1</code>，并设置<code>errno</code>表示错误类型。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> socket_fd = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>); <span class="comment">/* 创建套接字 */</span></span><br><span class="line"><span class="type">char</span> sendbuf[<span class="number">32</span>]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">int</span> sendbuflen = <span class="number">32</span>;</span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line">ret = send(socket_fd, sendbuf, sendbuflen, <span class="number">0</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>send()</code>成功返回，也并不表示连接的另一端的进程就一定接收了数据，我们所能保证的只是当<code>send()</code>成功返回时，数据已经被无错误的发送到网络驱动程序上。</p>
<h4 id="2-2-2-使用实例-1"><a href="#2-2-2-使用实例-1" class="headerlink" title="2.2.2 使用实例"></a><font size=3>2.2.2 使用实例</font></h4><p>暂无</p>
<h2 id="3-recvfrom-sendto"><a href="#3-recvfrom-sendto" class="headerlink" title="3.recvfrom()/sendto()"></a><font size=3>3.<code>recvfrom()/sendto()</code></font></h2><p><code>recvfrom()</code>和<code>sendto()</code>一般用于在面向无连接的数据报<code>socket</code>方式下进行数据传输。也就是说，这两个函数一般用于<code>UDP</code>协议编程中。</p>
<h3 id="3-1-recvfrom"><a href="#3-1-recvfrom" class="headerlink" title="3.1 recvfrom()"></a><font size=3>3.1 <code>recvfrom()</code></font></h3><h4 id="3-1-1-函数说明"><a href="#3-1-1-函数说明" class="headerlink" title="3.1.1 函数说明"></a><font size=3>3.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 2 recvfrom</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">recvfrom</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">void</span> *buf, <span class="type">size_t</span> len, <span class="type">int</span> flags, <span class="keyword">struct</span> sockaddr *src_addr, <span class="type">socklen_t</span> *addrlen)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数可以用于接收<code>socket</code>套接字的数据，并获取客户端的<code>IP</code>和端口号信息。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sockfd</code>：<code>int</code>类型，表示已打开的<code>socket</code>描述符。</li>
<li><code>buf</code>：<code>void</code>类型指针变量，表示接收数据的缓冲区。</li>
<li><code>len</code>：<code>size_t</code>类型，表示需要读取的字节数，不应超过<code>buf</code>。</li>
<li><code>flags</code>：<code>int</code>类型，指定一些标志用于控制如何接收数据。一般来说，我们这里会选择填<code>0</code>。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看flags常见可取值及含义 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>标志</td><td align="center">描述</td></tr>    <tr><td align="center" width=150px>MSG_CMSG_CLOEXEC</td><td align="left">为UNIX域套接字上接收的文件描述符设置执行时关闭标志</td></tr>    <tr><td align="center" width=150px>MSG_DONTWAIT</td><td align="left">启动非阻塞操作（相当于O_NONBLOCK）</td></tr>    <tr><td align="center" width=150px>MSG_ERRQUEUE</td><td align="left">接收错误信息作为辅助数据</td></tr>    <tr><td align="center" width=150px>MSG_OOB</td><td align="left">如果协议支持，获取带外数据</td></tr>    <tr><td align="center" width=150px>MSG_PEEK</td><td align="left">返回数据包内容而不真正取走数据包</td></tr>    <tr><td align="center" width=150px>MSG_TRUNC</td><td align="left">即使数据包被截断，也返回数据包的长度</td></tr>    <tr><td align="center" width=150px>MSG_WAITALL</td><td align="left">等待直到所有的数据可用（仅SOCK_STREAM）</td></tr></table>
              </div>
            </details>

<ul>
<li><code>src_addr</code>：<code>struct sockaddr</code>类型结构体指针变量，这是一个传出参数，里边保存了接收的数据的来源信息，包括了客户端的<code>IP</code>和端口号。这个参数其实与<code>bind()</code>函数的第二个参数的用法类似，不过这里是一个结构体指针变量。我们一般都会选择使用<code>sockaddr_in</code>或者<code>sockaddr_in6</code>来获取数据发送方的信息。但是如果我们对客户端的<code>IP</code>地址与端口号这些信息不感兴趣，可以把<code>addr</code>置为空指针<code>NULL</code>。</li>
<li><code>addrlen</code>：<code>socklen_t</code>类型指针变量，这个参数用于指定<code>src_addr</code>所指向的结构体对应的字节长度，一般由<code>sizeof</code>求得。如果<code>src_addr</code>置为空指针<code>NULL</code>，这个参数其实就没有什么太大意义了，就可以也置<code>NULL</code>。</li>
</ul>
<p><strong>【返回值】</strong><code>ssize_t</code>类型（表示有符号的<code>size_t</code>），成功时返回实际读取的字节数；出错时返回<code>-1</code>，并设置<code>errno</code>表示错误类型。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> socket_fd = socket(AF_INET, SOCK_DGRAM, <span class="number">0</span>); <span class="comment">/* 创建套接字 */</span></span><br><span class="line"><span class="type">char</span> recvbuf[<span class="number">32</span>]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">int</span> recvbuflen = <span class="number">32</span>;</span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line">ret = recvfrom(socket_fd, recvbuf, recvbuflen, <span class="number">0</span>, <span class="literal">NULL</span>, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）当该函数最后两个参数为<code>NULL</code>的时候，它可以等价于<code>recv()</code>，即：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">recv(sockfd, buf, len, flags);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* is equivalent to */</span></span><br><span class="line"></span><br><span class="line">recvfrom(sockfd, buf, len, flags, <span class="literal">NULL</span>, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure>

<p>（2）该函数会<strong>阻塞等待</strong>客户端数据的到来。</p>
<h4 id="3-1-2-使用实例"><a href="#3-1-2-使用实例" class="headerlink" title="3.1.2 使用实例"></a><font size=3>3.1.2 使用实例</font></h4><p>暂无</p>
<h3 id="3-2-sendto"><a href="#3-2-sendto" class="headerlink" title="3.2 sendto()"></a><font size=3>3.2 <code>sendto()</code></font></h3><h4 id="3-2-1-函数说明"><a href="#3-2-1-函数说明" class="headerlink" title="3.2.1 函数说明"></a><font size=3>3.2.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 2 sendto</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">sendto</span><span class="params">(<span class="type">int</span> sockfd, <span class="type">const</span> <span class="type">void</span> *buf, <span class="type">size_t</span> len, <span class="type">int</span> flags, <span class="type">const</span> <span class="keyword">struct</span> sockaddr *dest_addr, <span class="type">socklen_t</span> addrlen)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数可以用于向<code>socket</code>套接字发送数据。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sockfd</code>：<code>int</code>类型，表示已打开的<code>socket</code>描述符。</li>
<li><code>buf</code>：<code>void</code>类型指针变量，表示要发送数据的缓冲区。</li>
<li><code>len</code>：<code>size_t</code>类型，表示需要发送的数据的字节数，不应超过<code>buf</code>。</li>
<li><code>flags</code>：<code>int</code>类型，指定一些标志用于控制如何发送数据。一般来说，这里我们选择<code>0</code>。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看flags常见可取值及含义 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>标志</td><td align="center">描述</td></tr>    <tr><td align="center" width=150px>MSG_CONFIRM</td><td align="left">提供链路层反馈以保持地址映射有效</td></tr>    <tr><td align="center" width=150px>MSG_DONTROUTE</td><td align="left">勿将数据包路由出本地网络</td></tr>    <tr><td align="center" width=150px>MSG_DONTWAIT </td><td align="left">允许非阻塞操作（等价于使用 O_NONBLOCK）</td></tr>    <tr><td align="center" width=150px>MSG_EOR</td><td align="left">如果协议支持，标志记录结束</td></tr>    <tr><td align="center" width=150px>MSG_MORE</td><td align="left">延迟发送数据包允许写更多数据</td></tr>    <tr><td align="center" width=150px>MSG_NOSIGNAL</td><td align="left">在写无连接的套接字时不产生 SIGPIPE 信号</td></tr>    <tr><td align="center" width=150px>MSG_OOB</td><td align="left">如果协议支持，发送带外数据</td></tr></table>
              </div>
            </details>

<ul>
<li><code>dest_addr</code>：<code>struct sockaddr</code>类型结构体指针变量，里边保存对方（接收数据一方）的<code>IP</code>和端口号。这个参数其实与<code>bind()</code>函数的第二个参数的用法类似，不过这里是一个结构体指针变量。我们一般都会选择使用<code>sockaddr_in</code>或者<code>sockaddr_in6</code>来获取数据发送方的信息。但是如果我们对客户端的<code>IP</code>地址与端口号这些信息不感兴趣，可以把<code>addr</code>置为空指针<code>NULL</code>。</li>
<li><code>addrlen</code>：<code>socklen_t</code>类型，这个参数用于指定<code>dest_addr</code>所指向的结构体对应的字节长度，一般由<code>sizeof</code>求得。如果<code>dest_addr</code>置为空指针<code>NULL</code>，这个参数其实就没有什么太大意义了，就可以为<code>0</code>了。</li>
</ul>
<p><strong>【返回值】</strong><code>ssize_t</code>类型（表示有符号的<code>size_t</code>），成功时返回发送的字节数；出错时返回<code>-1</code>，并设置<code>errno</code>表示错误类型。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;strings.h&gt;</span>            <span class="comment">/* bzero exit */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;arpa/inet.h&gt;</span>          <span class="comment">/* htons htonl */</span></span></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> socket_fd = socket(AF_INET, SOCK_DGRAM, <span class="number">0</span>); <span class="comment">/* 创建套接字 */</span></span><br><span class="line"><span class="type">char</span> sendbuf[<span class="number">32</span>]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">sin</span>;</span></span><br><span class="line">bzero (&amp;<span class="built_in">sin</span>, <span class="keyword">sizeof</span> (<span class="built_in">sin</span>));</span><br><span class="line"><span class="built_in">sin</span>.sin_family = AF_INET;       <span class="comment">/* 设置协议族 */</span></span><br><span class="line"><span class="built_in">sin</span>.sin_port = htons (<span class="number">5010</span>);	<span class="comment">/* 网络字节序的端口号, 一个自定义宏 */</span></span><br><span class="line"><span class="built_in">sin</span>.sin_addr.s_addr = htonl (<span class="string">&quot;192.168.1.1&quot;</span>);<span class="comment">/* 可以绑定任意IP，后边说明 */</span></span><br><span class="line"></span><br><span class="line">sendto(fd, sendbuf, <span class="built_in">strlen</span>(sendbuf), <span class="number">0</span>, (<span class="keyword">struct</span> sockaddr *)&amp;<span class="built_in">sin</span>, <span class="keyword">sizeof</span>(<span class="built_in">sin</span>)); </span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>当该函数最后两个参数为<code>NULL</code>的时候，它可以等价于<code>recv()</code>，即：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">send(sockfd, buf, len, flags);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* is equivalent to */</span></span><br><span class="line"></span><br><span class="line">sendto(sockfd, buf, len, flags, <span class="literal">NULL</span>, <span class="number">0</span>);</span><br></pre></td></tr></table></figure>

<h4 id="3-2-2-使用实例"><a href="#3-2-2-使用实例" class="headerlink" title="3.2.2 使用实例"></a><font size=3>3.2.2 使用实例</font></h4><p>暂无</p>
<h1 id="五、socket缓冲区和阻塞模式"><a href="#五、socket缓冲区和阻塞模式" class="headerlink" title="五、socket缓冲区和阻塞模式"></a><font size=3>五、<code>socket</code>缓冲区和阻塞模式</font></h1><h2 id="1-socket缓冲区"><a href="#1-socket缓冲区" class="headerlink" title="1. socket缓冲区"></a><font size=3>1. <code>socket</code>缓冲区</font></h2><h3 id="1-1-缓冲区说明"><a href="#1-1-缓冲区说明" class="headerlink" title="1.1 缓冲区说明"></a><font size=3>1.1 缓冲区说明</font></h3><p>每个 <code>socket</code> 被创建后，都会分配两个缓冲区，<strong>输入缓冲区</strong>和<strong>输出缓冲区</strong>。<code>write()/send() </code>并不立即向网络中传输数据，而是先将数据写入缓冲区中，再由<code>TCP</code>协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区，函数就可以成功返回，不管它们有没有到达目标机器，也不管它们何时被发送到网络，因为这些都是<code>TCP</code>协议负责的事情。<code>read()/recv()</code> 函数也是如此，也从输入缓冲区中读取数据，而不是直接从网络中读取。</p>
<p><code>TCP</code>协议独立于 <code>write()/send()</code> 函数，数据有可能刚被写入缓冲区就发送到网络，也可能在缓冲区中不断积压，多次写入的数据被一次性发送到网络，这取决于当时的网络情况、当前线程是否空闲等诸多因素，不由我们控制。</p>
<p><code>TCP</code>协议套接字的<code>I/O</code>缓冲区如下所示：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/LV06-03-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-02-scoket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3/img/image-20220628162706259.png" alt="image-20220628162706259" style="zoom:50%;" />

<p><code>I/O</code>缓冲区的特性总结如下：</p>
<ul>
<li><code>I/O</code>缓冲区在每个<code>TCP</code>套接字中单独存在；</li>
<li><code>I/O</code>缓冲区在创建套接字时自动生成；</li>
<li>即使关闭套接字也会继续传送输出缓冲区中遗留的数据；</li>
<li>关闭套接字将丢失输入缓冲区中的数据。</li>
</ul>
<h3 id="1-2-TCP协议缓冲区大小获取"><a href="#1-2-TCP协议缓冲区大小获取" class="headerlink" title="1.2 TCP协议缓冲区大小获取"></a><font size=3>1.2 <code>TCP</code>协议缓冲区大小获取</font></h3><ul>
<li>方法一</li>
</ul>
<p>输入输出缓冲区的默认大小可以通过 <code>getsockopt()</code> 函数（这个函数会在后边的网络属性设置中详细学习）获取：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>          <span class="comment">/* See NOTES */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> arc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">unsigned</span> <span class="type">int</span> sendBuff;</span><br><span class="line">	<span class="type">unsigned</span> <span class="type">int</span> recvBuff;</span><br><span class="line">	<span class="type">socklen_t</span> optLen = <span class="keyword">sizeof</span>(<span class="type">int</span>);</span><br><span class="line">	<span class="type">int</span> socket_fd = socket_fd = socket(AF_INET, SOCK_STREAM, <span class="number">0</span>);</span><br><span class="line">	getsockopt(socket_fd, SOL_SOCKET, SO_SNDBUF, (<span class="type">char</span>*)&amp;sendBuff, &amp;optLen);</span><br><span class="line">	getsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, (<span class="type">char</span>*)&amp;recvBuff, &amp;optLen);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;sendBuff length: %dKB\n&quot;</span>, sendBuff / <span class="number">1024</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;recvBuff length: %dKB\n&quot;</span>, recvBuff / <span class="number">1024</span>);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>然后在终端输入以下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure>

<p>然后，终端会有以下信息显示：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sendBuff length: 16KB</span><br><span class="line">recvBuff length: 128KB</span><br></pre></td></tr></table></figure>



<ul>
<li>方法二</li>
</ul>
<p>我们在终端输入以下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cat /proc/sys/net/ipv4/tcp_wmem  # 获取 TCP 发送缓冲区大小</span><br><span class="line">cat /proc/sys/net/ipv4/tcp_rmem  # 获取 TCP 接收缓冲区大小</span><br></pre></td></tr></table></figure>

<p>上边是两条命令，我们将会看到如下的信息输出：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/LV06-03-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B-02-scoket%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3/img/image-20220628171626877.png" alt="image-20220628171626877" style="zoom:50%;" />

<p>我们可以看到每条命令都是打印了三个数据，这三个数据分别为：最小值、默认值和最大值（我的系统是<code>Ubuntu21.04</code>的<code>64</code>位版本）。</p>
<h3 id="1-3-BUFSIZ"><a href="#1-3-BUFSIZ" class="headerlink" title="1.3 BUFSIZ"></a><font size=3>1.3 <code>BUFSIZ</code></font></h3><p>在有些网络编程的程序中看到过这个宏，找半天没找到定义，后来才发现这是<code>C</code>库中定义的一个宏，在网上搜，都说它定义在<code>stdio.h</code>中，我们可以使用以下命令查看该文件的位置：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">locate stdio.h</span><br></pre></td></tr></table></figure>

<p>然后我们选择打开路径为<code>/usr/include/stdio.h</code>的这个文件：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /usr/include/stdio.h</span><br></pre></td></tr></table></figure>

<p>就会发现有如下宏：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Default buffer size.  */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> BUFSIZ 8192</span></span><br></pre></td></tr></table></figure>

<p>这个宏的大小是<code>8192</code>，所以我们可以通过它来作为数组的大小，可以用于网络编程的数据输入输出缓冲区数组的定义。</p>
<h2 id="2-阻塞模式"><a href="#2-阻塞模式" class="headerlink" title="2. 阻塞模式"></a><font size=3>2. 阻塞模式</font></h2><p>对于<code>TCP</code>套接字（默认情况下），<code>TCP</code>套接字的阻塞模式如下：</p>
<ul>
<li>当使用 <code>write()/send() </code>发送数据时</li>
</ul>
<p>（1）首先会检查缓冲区，如果缓冲区的可用空间长度小于要发送的数据，那么 <code>write()/send() </code>会被阻塞（暂停执行），直到缓冲区中的数据被发送到目标机器，有足够的空间时，才唤醒 <code>write()/send()</code> 函数继续写入数据。</p>
<p>（2） 如果<code>TCP</code>协议正在向网络发送数据，那么输出缓冲区会被锁定，不允许写入，<code>write()/send() </code>也会被阻塞，直到数据发送完毕缓冲区解锁，<code>write()/send()</code> 才会被唤醒。</p>
<p>（3）如果要写入的数据大于缓冲区的最大长度，那么将分批写入。</p>
<p>（4）直到所有数据被写入缓冲区 <code>write()/send() </code>才能返回。</p>
<ul>
<li>当使用 <code>read()/recv()</code> 读取数据时</li>
</ul>
<p>（1）首先会检查缓冲区，如果缓冲区中有数据，那么就读取，否则函数会被阻塞，直到网络上有数据到来。</p>
<p>（2） 如果要读取的数据长度小于缓冲区中的数据长度，那么就不能一次性将缓冲区中的所有数据读出，剩余数据将不断积压，直到有 <code>read()/recv()</code> 函数再次读取。</p>
<p>（3）直到读取到数据后 <code>read()/recv()</code> 函数才会返回，否则就一直被阻塞。</p>
<blockquote>
<p>TCP套接字默认情况下是阻塞模式，也是最常用的。当然我们也可以更改为非阻塞模式。</p>
</blockquote>

    </div>

    
    
    

    <footer class="post-footer">




    <div>
        
            <div style="text-align:center;color: #ccc;font-size:14px;">
            ----------本文结束
            <i class="fas fa-fan fa-spin" style="color: #FF1493; font-size: 1rem"></i>
            感谢您的阅读----------
            </div>
        
    </div>





  
  <div class="my_post_copyright"> 
    <p><span>文章标题:</span><a href="/post/9661d1ba.html">LV06-03-网络编程-02-scoket编程接口</a></p>
    <p><span>文章作者:</span><a href="/" title="欢迎访问 《苏木》 的学习笔记">苏木</a></p>
    <p><span>发布时间:</span>2024年10月27日 - 11:49</p>
    <p><span>最后更新:</span>2025年06月14日 - 00:25</p>
    <p><span>原始链接:</span><a href="/post/9661d1ba.html" title="LV06-03-网络编程-02-scoket编程接口">https://sumumm.github.io/post/9661d1ba.html</a></p>
    <p><span>许可协议:</span><i class="fab fa-creative-commons"></i> <a rel="license" href= "https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank" title="Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)">署名-非商业性使用-禁止演绎 4.0 国际</a> 转载请保留原文链接及作者。</p>  
  </div>
  


          <div class="post-tags">
              <a href="/tags/LV06-%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/" rel="tag"><i class="fa fa-tag"></i> LV06-网络编程</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/post/dcd592e4.html" rel="prev" title="LV06-03-网络编程-03-TCP协议编程">
                  <i class="fa fa-angle-left"></i> LV06-03-网络编程-03-TCP协议编程
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/post/a2f3a956.html" rel="next" title="LV06-03-网络编程-01-socket基础">
                  LV06-03-网络编程-01-socket基础 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 2017 – 
    <span itemprop="copyrightYear">2025</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">苏木</span>
  </div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>站点总字数：</span>
    <span title="站点总字数">3.7m</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">225:26</span>
  </span>
</div>




    <span id="sitetime"></span>
    <script defer language=javascript>
        function siteTime()
        {
            window.setTimeout("siteTime()", 1000);
            var seconds = 1000;
            var minutes = seconds * 60;
            var hours = minutes * 60;
            var days = hours * 24;
            var years = days * 365;
            var today = new Date();
            var todayYear = today.getFullYear();
            var todayMonth = today.getMonth()+1;
            var todayDate = today.getDate();
            var todayHour = today.getHours();
            var todayMinute = today.getMinutes();
            var todaySecond = today.getSeconds();
            /*==================================================
            Date.UTC() -- 返回date对象距世界标准时间(UTC)1970年1月1日午夜之间的毫秒数(时间戳)
            year        - 作为date对象的年份，为4位年份值
            month       - 0-11之间的整数，做为date对象的月份
            day         - 1-31之间的整数，做为date对象的天数
            hours       - 0(午夜24点)-23之间的整数，做为date对象的小时数
            minutes     - 0-59之间的整数，做为date对象的分钟数
            seconds     - 0-59之间的整数，做为date对象的秒数
            microseconds - 0-999之间的整数，做为date对象的毫秒数
            ==================================================*/
            var t1 = Date.UTC(2017, 
                              5, 
                              19, 
                              0, 
                              0, 
                              0); //北京时间
            var t2 = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
            var diff = t2-t1;
            var diffYears = Math.floor(diff/years);
            var diffDays = Math.floor((diff/days)-diffYears*365);
            var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
            var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
            var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
            document.getElementById("sitetime").innerHTML="已在这里 "+diffYears+" 年 "+diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒";
        }
        siteTime();
    </script>



    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.umd.js" integrity="sha256-ytMJGN3toR+a84u7g7NuHm91VIR06Q41kMWDr2pq7Zo=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js" integrity="sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/fancybox.js"></script>

  <script src="/js/third-party/pace.js"></script>


  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>


 
        <div id="click-show-text"
            data-mobile = false
            data-text = 富强,民主,文明,和谐,自由,平等,公正,法制,爱国,敬业,诚信,友善
            data-fontsize = 15px
            data-random= false>
        </div>
       

      
        <script async src=https://cdn.jsdelivr.net/npm/hexo-next-mouse-effect@latest/click/showText.js></script>
      

      
    




    <script async src="/js/fancybox_param.js"></script>





<!-- APlayer本体 -->



</body>
</html>
